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

Tomcat 在JavaWeb应用程序中从应用程序服务器外部提供静态数据的最简单方法,tomcat,jakarta-ee,servlets,static-content,Tomcat,Jakarta Ee,Servlets,Static Content,我有一个Java web应用程序在Tomcat上运行。我想加载静态图像,这些图像将显示在Web UI和应用程序生成的PDF文件中。此外,还将通过Web UI上传添加和保存新图像 通过将静态数据存储在web容器中来实现这一点不是问题,但是从web容器外部存储和加载静态数据让我头疼 此时,我不希望使用单独的web服务器(如Apache)来提供静态数据。我也不喜欢将图像以二进制形式存储在数据库中的想法 我见过一些建议,比如将图像目录作为指向web容器外部目录的符号链接,但是这种方法在Windows和*

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

通过将静态数据存储在web容器中来实现这一点不是问题,但是从web容器外部存储和加载静态数据让我头疼

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

我见过一些建议,比如将图像目录作为指向web容器外部目录的符号链接,但是这种方法在Windows和*nix环境下都有效吗


有些人建议编写一个过滤器或servlet来处理图像服务,但这些建议非常模糊和高层次,没有指向如何实现这一点的更详细信息。

您可以通过将图像放在固定路径上(例如:/var/images或c:\images)来实现,在应用程序设置中添加一个设置(在我的示例中由settings.class表示),然后像这样加载它们,加载到您的
HttpServlet
中:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
FileInputStream fis = new FileInputStream(filename);

int b = 0;
while ((b = fis.read()) != -1) {
        response.getOutputStream().write(b);
}
或者,如果要操纵图像:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
File imageFile = new File(filename);
BufferedImage image = ImageIO.read(imageFile);
ImageIO.write(image, "image/png", response.getOutputStream());
然后html代码将是

当然,您应该考虑提供不同的内容类型——“image/jpeg”,例如基于文件扩展名。您还应该提供一些缓存

此外,通过提供宽度和高度参数作为参数,并使用
image.getScaledInstance(w,h,image.SCALE\u SMOOTH
),您可以使用此servlet对图像进行质量重缩放,当然要考虑性能

我见过一些建议,比如将图像目录作为指向web容器外部目录的符号链接,但是这种方法在Windows和*nix环境下都有效吗

如果您遵守*nix文件系统路径规则(即,在
/path/to/files
中只使用前斜杠),那么它也可以在Windows上工作,而不需要处理难看的
File.separator
字符串连接。但是,只能在调用此命令的同一工作磁盘上对其进行扫描。因此,如果Tomcat安装在
C:
上,那么
/path/to/files
实际上会指向
C:\path\to\files

如果这些文件都位于webapp之外,并且您想让Tomcat的
DefaultServlet
来处理它们,那么在Tomcat中基本上需要做的就是将以下上下文元素添加到
/conf/server.xml
标记中:


这样就可以通过
http://example.com/files/...
。对于基于Tomcat的服务器,如JBoss EAP 6.x或更早版本,方法基本相同,另请参阅。可以找到GlassFish/Payara配置示例,也可以找到WildFly配置示例

如果您想自己控制文件的读写,那么您需要为此创建一个
Servlet
,它基本上只获取文件的
InputStream
,例如
FileInputStream
,并将其写入
HttpServletResponse
OutputStream

在响应中,您应该设置
内容类型
标题,以便客户端知道要将哪个应用程序与提供的文件关联。而且,您应该设置
内容长度
标题,以便客户端可以计算下载进度,否则它将是未知的。而且,如果需要另存为对话框,则应将
内容处置
标题设置为
附件
,否则客户端将尝试以内联方式显示它。最后,只需将文件内容写入响应输出流

下面是此类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());
    }

}
当映射到例如
/files/*
url模式时,您可以通过
http://example.com/files/image.png
。这样,您可以比
DefaultServlet
对请求有更多的控制,例如提供一个默认映像(例如,
如果(!file.exists())file=new file(“/path/to/files”,“404.gif”)
等等)。此外,在
request.getParameter()
之前,最好使用
request.getPathInfo()
,因为它对SEO更友好,否则IE在另存为过程中不会选择正确的文件名

您可以重用相同的逻辑为数据库中的文件提供服务。只需将
新文件inputstream()
替换为
结果集#getInputStream()

希望这有帮助

另见:
  • (支持HTTP缓存)

如果您决定分派到
FileServlet
,则还需要
context.xml
中的
allowLinking=“true”
,以便允许
FileServlet
遍历符号链接


请参阅要求:从WEBROOT目录外部或本地磁盘访问静态资源(图像/视频等)

第一步:
在tomcat服务器的webapps下创建一个文件夹,假设文件夹名为myproj

第2步:
在myproj下创建一个WEB-INF文件夹,在该文件夹下创建一个简单的WEB.xml文件

web.xml下的代码

<web-app>
</web-app>
第三步:
现在在以下位置创建一个名为myproj.xml的xml文件

c:\programfile\apachesoftwarefoundation\tomcat\conf\catalina\localhost
myproj.xml中的代码:

<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" /> 
第5步:
现在创建一个名为index.html的.html文档,并放在e:\myproj下

index.html下的代码 欢迎来到Myproj

上述步骤4和步骤5的目录结构如下

E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml
步骤6:
<web-app>
</web-app>
E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml
http://localhost:8080/myproj    
http://localhost:8080/myproj/images/myfoto.jpg
 <Context docBase="c:/dirtoshare" path="/dir" />
    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>
<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">
<img src="/images/foo.jsp" alt="Foo" height="142" width="142">
@Path("/pic")
public Response get(@QueryParam("url") final String url) {
    String picUrl = URLDecoder.decode(url, "UTF-8");

    return Response.ok(sendPicAsStream(picUrl))
            .header(HttpHeaders.CONTENT_TYPE, "image/jpg")
            .build();
}

private StreamingOutput sendPicAsStream(String picUrl) {
    return output -> {
        try (InputStream is = (new URL(picUrl)).openStream()) {
            ByteStreams.copy(is, output);
        }
    };
}