Tomcat 在servlet应用程序中保存上载文件的推荐方法
我了解到,无论如何都不应该将文件保存在服务器中,因为它不是可移植的、事务性的,并且需要外部参数。但是,考虑到我需要一个针对tomcat(7)的tmp解决方案,并且我对服务器机器拥有(相对)控制权,我想知道:Tomcat 在servlet应用程序中保存上载文件的推荐方法,tomcat,servlets,file-upload,servlet-3.0,Tomcat,Servlets,File Upload,Servlet 3.0,我了解到,无论如何都不应该将文件保存在服务器中,因为它不是可移植的、事务性的,并且需要外部参数。但是,考虑到我需要一个针对tomcat(7)的tmp解决方案,并且我对服务器机器拥有(相对)控制权,我想知道: 保存文件的最佳位置是什么?我应该把它保存在/WEB-INF/uploads(建议不要)或$CATALINA_BASE下的某个地方(请参阅)还是?JavaEE6教程(:wtf:)。注意:该文件不应以任何方式下载 我应该设置一个配置参数吗?我很欣赏一些代码(我宁愿给它一个相对路径——因此它至少
- 保存文件的最佳位置是什么?我应该把它保存在
(建议不要)或/WEB-INF/uploads
下的某个地方(请参阅)还是?JavaEE6教程(:wtf:)。注意:该文件不应以任何方式下载$CATALINA_BASE
- 我应该设置一个配置参数吗?我很欣赏一些代码(我宁愿给它一个相对路径——因此它至少是Tomcat可移植的)——看起来很有希望——但显然需要一个绝对路径
- 我想解释一下这种方法相对于数据库/JCR存储库的缺点
最好是一个易于转换为使用DB或JCR实现(如)的解决方案。将其存储在除IDE的项目文件夹(又称服务器的部署文件夹)以外的任何可访问位置,原因如下:
@MultipartConfig(location)
没有指定最终上载目标,但是案例文件大小的临时存储位置超过了内存存储阈值
因此,最终存储位置的路径可以通过以下任一方式定义:
- 硬编码:
File uploads = new File("/path/to/uploads");
- 环境变量通过
:设置上传位置=/path/to/uploads
File uploads = new File(System.getenv("UPLOAD_LOCATION"));
File uploads = new File(System.getProperty("upload.location"));
File uploads = new File(properties.getProperty("upload.location"));
File uploads = new File(getServletContext().getInitParameter("upload.location"));
- 通过
启动服务器期间的VM参数:-Dupload.location=“/path/to/uploads”
文件条目为*.properties
:upload.location=/path/to/uploads
File uploads = new File(System.getenv("UPLOAD_LOCATION"));
File uploads = new File(System.getProperty("upload.location"));
File uploads = new File(properties.getProperty("upload.location"));
File uploads = new File(getServletContext().getInitParameter("upload.location"));
web.xml
名称
和值upload.location
:/path/to/uploads
File uploads = new File(System.getenv("UPLOAD_LOCATION"));
File uploads = new File(System.getProperty("upload.location"));
File uploads = new File(properties.getProperty("upload.location"));
File uploads = new File(getServletContext().getInitParameter("upload.location"));
- 如果有,请使用服务器提供的位置,例如:
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);
}
如何在JSP/Servlet中获取part
,以及如何在JSF中获取part
在中得到了回答
注意:请勿使用,因为它解释了相对于@MultipartConfig(location)
中定义的临时存储位置的路径。另外,在读/写过程中,不正确地使用读卡器
/写卡器
而不是输入流
/输出流
将字节转换为字符,从而绝对确保不会损坏二进制文件,如PDF文件或图像文件
另见:
- (JSF目标明确,但原理基本相同)
- (如果你想把它送回去)
@SuppressWarnings("serial")
@WebServlet("/")
@MultipartConfig
public final class DataCollectionServlet extends Controller {
private static final String UPLOAD_LOCATION_PROPERTY_KEY="upload.location";
private String uploadsDirName;
@Override
public void init() throws ServletException {
super.init();
uploadsDirName = property(UPLOAD_LOCATION_PROPERTY_KEY);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// ...
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Collection<Part> parts = req.getParts();
for (Part part : parts) {
File save = new File(uploadsDirName, getFilename(part) + "_"
+ System.currentTimeMillis());
final String absolutePath = save.getAbsolutePath();
log.debug(absolutePath);
part.write(absolutePath);
sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp);
}
}
// helpers
private static String getFilename(Part part) {
// courtesy of BalusC : http://stackoverflow.com/a/2424824/281545
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String filename = cd.substring(cd.indexOf('=') + 1).trim()
.replace("\"", "");
return filename.substring(filename.lastIndexOf('/') + 1)
.substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
}
以及/WEB-INF/app.properties:
upload.location=C:/_/
HTH如果您发现一个bug,请告诉我。当文件大小超过内存存储阈值时,
@MultipartConfig(location)
指定服务器应该使用的临时存储位置,而不是您最终希望存储它的永久存储位置。该值默认为由系统属性java.io.tmpdir
标识的路径。另请参见对失败的JSF尝试的相关回答:谢谢-希望我听起来不是白痴,但这段引用自部分。结合一些未知的“cut”(vs copy)方法编写>,比如说一些apache lib可以帮我省去自己编写字节的麻烦-并重新创建已经存在的文件(另请参见)是的,如果您已经使用Servlet 3.0,那么可以使用Part\write()
。我用它更新了答案。非常感谢您不断更新帖子-Tomcat是否有像“jboss.server.data.dir”
这样的属性?不,它没有。关于我的最后一种方法,请看如果我想要一个如此独立的解决方案,它在两种情况下都能工作(win/ux),该怎么办?我是否必须设置不同的upload.location路径或有其他提示?