java - 在 Java Web 应用程序中从应用程序服务器外部提供静态数据的最简单方法

标签 java tomcat servlets jakarta-ee static-content

我有一个在 Tomcat 上运行的 Java 网络应用程序。我想加载将同时显示在 Web UI 和应用程序生成的 PDF 文件中的静态图像。还将通过 Web UI 上传添加和保存新图像。

通过将静态数据存储在 Web 容器中来执行此操作不是问题,但是从 Web 容器外部存储和加载它们让我很头疼。

此时我不希望使用像 Apache 这样的单独 Web 服务器来提供静态数据。我也不喜欢将图像以二进制形式存储在数据库中的想法。

我看到了一些建议,例如将图像目录作为指向 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并将其写入 OutputStreamHttpServletResponse .

在响应中,您应该设置 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/38695019/

相关文章:

java - 表示日历对象的最佳规范字符串?

java - Heroku - 我部署的 Spring MVC 项目不起作用

java - 从 Tomcat 服务器迁移到 JBoss 时数据源错误?

Java Servlet 在浏览器中打印 "language/content type/page encoding"行

java - Java中的默认值和初始化

java - 有没有更好的方法来使用等待/通知与 AtomicInteger 连接

java - Wicket AjaxLink isLinkEnabled() = false 呈现可点击的范围

java - 我可以将我的 tomcat 实例发布到同一 wifi 网络中的其他计算机吗?互联网怎么样?

android - 通过 HttpPost 从 Android 发送图像(jpg)到 Servlet(WebServer)

java - 如何使用 servlet 为 Eclipse 中的所有 html 和 jsp 页面维护唯一的 session ?