我有一个在 Tomcat 上运行的 Java Web 应用程序。我想加载将在 Web UI 和应用程序生成的 PDF 文件中显示的静态图像。此外,还将通过 Web UI 上传来添加和保存新图像。
通过将静态数据存储在 Web 容器中来做到这一点不是问题,但从 Web 容器外部存储和加载它们却让我头疼。
此时我不想使用单独的 Web 服务器(例如 Apache)来提供静态数据。我也不喜欢将图像以二进制形式存储在数据库中的想法。
我看到过一些建议,例如将图像目录作为指向 Web 容器外部目录的符号链接(symbolic link),但是这种方法在 Windows 和 *nix 环境中都适用吗?
有些人建议编写一个过滤器或 servlet 来处理图像服务,但这些建议非常模糊且高级,没有指向如何完成此操作的更详细信息。
最佳答案
I've seen some suggestions like having the image directory being a symbolic link pointing to a directory outside the web container, but will this approach work both on Windows and *nix environments?
如果您遵守 *nix 文件系统路径规则(即您仅使用正斜杠,如 /path/to/files
),那么它也可以在 Windows 上运行,而无需摆弄丑陋的 File.separator
。字符串连接。然而,它只会在调用该命令的同一工作磁盘上进行扫描。例如,如果 Tomcat 安装在 C:
上然后/path/to/files
实际上会指向 C:\path\to\files
.
如果文件都位于webapp之外,并且你想要Tomcat的DefaultServlet
要处理它们,那么您在 Tomcat 中基本上需要做的就是将以下 Context 元素添加到 /conf/server.xml
里面<Host>
标签:
<Context docBase="/path/to/files" path="/files" />
这样就可以通过 http://example.com/files/...
访问它们。对于基于 Tomcat 的服务器,例如 JBoss EAP 6.x 或更早版本,方法基本相同,另请参阅 here 。 GlassFish/Payara 配置示例可参见here和WildFly配置示例可以找到here .
如果你想自己控制读/写文件,那么你需要创建一个 Servlet
为此,基本上只得到 InputStream
例如 FileInputStream
风格的文件并将其写入 OutputStream
HttpServletResponse
的.
在响应中,您应该设置 Content-Type
header ,以便客户端知道哪个应用程序与所提供的文件关联。并且,您应该设置 Content-Length
header 以便客户端可以计算下载进度,否则将未知。并且,您应该设置 Content-Disposition
标题为 attachment
如果您想要一个“另存为”对话框,否则客户端将尝试内联显示它。最后只需将文件内容写入响应输出流即可。
下面是此类 servlet 的基本示例:
@WebServlet("/files/*")
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String filename = URLDecoder.decode(request.getPathInfo().substring(1), "UTF-8");
File file = new File("/path/to/files", filename);
response.setHeader("Content-Type", getServletContext().getMimeType(filename));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
Files.copy(file.toPath(), response.getOutputStream());
}
}
当映射到url-pattern
时例如/files/*
,那么你可以通过 http://example.com/files/image.png
来调用它。通过这种方式,您可以比DefaultServlet
更好地控制请求。这样做,例如提供默认图像(即 if (!file.exists()) file = new File("/path/to/files", "404.gif")
左右)。还使用request.getPathInfo()
以上优先request.getParameter()
因为它对 SEO 更友好,否则 IE 在“另存为”期间将无法选择正确的文件名。
您可以重用相同的逻辑来提供数据库中的文件。只需替换 new FileInputStream()
通过ResultSet#getInputStream()
.
另请参阅:
关于java - 在 Java Web 应用程序中从应用程序服务器外部提供静态数据的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61892270/