Tomcat 在JavaWeb应用程序中从应用程序服务器外部提供静态数据的最简单方法
我有一个Java web应用程序在Tomcat上运行。我想加载静态图像,这些图像将显示在Web UI和应用程序生成的PDF文件中。此外,还将通过Web UI上传添加和保存新图像 通过将静态数据存储在web容器中来实现这一点不是问题,但是从web容器外部存储和加载静态数据让我头疼 此时,我不希望使用单独的web服务器(如Apache)来提供静态数据。我也不喜欢将图像以二进制形式存储在数据库中的想法 我见过一些建议,比如将图像目录作为指向web容器外部目录的符号链接,但是这种方法在Windows和*nix环境下都有效吗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和*
有些人建议编写一个过滤器或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);
}
};
}