我需要使用 JSF <h:graphicimage>
显示位于 Web 应用程序部署文件夹之外的图像标签或 HTML <img>
标签。我怎样才能实现这一目标?
最佳答案
到目前为止,它必须可以通过公共(public) URL 访问。因此,<img src>
最终必须引用 http://
URI,而不是像 file://
这样的东西URI 左右。最终,HTML 源在最终用户的计算机上执行,并且图像在解析 HTML 源期间由网络浏览器单独下载。当网络浏览器遇到 file://
URI 例如 C:\path\to\image.png
,然后它将在最终用户自己的本地磁盘文件系统而不是网络服务器的磁盘文件系统中查找图像。如果网络浏览器运行在与网络服务器物理上不同的机器上,这显然是行不通的。
有几种方法可以实现这一目标:
如果您对图像文件夹有完全控制权,则只需删除包含所有图像的文件夹,例如
/images
直接在servletcontainer的deploy文件夹中,如/webapps
文件夹(如果是 Tomcat)和/domains/domain1/applications
如果是 GlassFish,则为文件夹。无需进一步配置。或者,向服务器添加一个新的 Web 应用程序上下文,该上下文指向包含这些图像的文件夹的绝对磁盘文件系统位置。如何做到这一点取决于所使用的容器。以下示例假设图像位于
/path/to/images
并且您想通过 http://.../images 访问它们.如果是 Tomcat,请将以下新条目添加到 Tomcat 的
/conf/server.xml
中里面<Host>
:<Context docBase="/path/to/images" path="/images" />
如果是 GlassFish,请将以下条目添加到
/WEB-INF/glassfish-web.xml
:<property name="alternatedocroot_1" value="from=/images/* dir=/path/to" />
如果是 WildFly,请在
<host name="default-host">
内添加以下条目的/standalone/configuration/standalone.xml
...<location name="/images" handler="images-content" />
...并进一步向下
<handlers>
完全相同的条目<subsystem>
如上<location>
:<file name="images-content" path="/path/to/images" />
或者,创建一个
Servlet
它将图像从磁盘流式传输到响应:@WebServlet("/images/*") public class ImageServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getPathInfo().substring(1); File file = new File("/path/to/images", filename); response.setHeader("Content-Type", getServletContext().getMimeType(filename)); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\""); Files.copy(file.toPath(), response.getOutputStream()); } }
如果您碰巧使用 OmniFaces,则
FileServlet
可能很有用,因为它还考虑了头部、缓存和范围请求。或者,使用 OmniFaces
<o:graphicImage>
它支持返回byte[]
的 bean 属性或InputStream
:@Named @ApplicationScoped public class Bean { public InputStream getImage(String filename) { return new FileInputStream(new File("/path/to/images", filename)); } }
或者,使用 PrimeFaces
<p:graphicImage>
它支持返回 PrimeFaces 特定的 bean 方法StreamedContent
.@Named @ApplicationScoped public class Bean { public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { // So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL. return new DefaultStreamedContent(); } else { // So, browser is requesting the image. Return a real StreamedContent with the image bytes. String filename = context.getExternalContext().getRequestParameterMap().get("filename"); return new DefaultStreamedContent(new FileInputStream(new File("/path/to/images", filename))); } } }
对于第一种方式以及第二种方式的 Tomcat 和 WildFly 方式,图像将通过 http://example.com/images/filename.ext 提供。因此可以在纯 HTML 中引用,如下所示
<img src="/images/filename.ext" />
对于第二种方式和第三种方式的 GlassFish 方法,图像将通过 http://example.com/context/images/filename.ext 提供。因此可以在纯 HTML 中引用,如下所示
<img src="#{request.contextPath}/images/filename.ext" />
或者在 JSF 中如下所示(上下文路径会自动添加到前面)
<h:graphicImage value="/images/filename.ext" />
第四种方式的OmniFaces方法,引用如下
<o:graphicImage value="#{bean.getImage('filename.ext')}" />
第五种方式的PrimeFaces方法,引用如下:
<p:graphicImage value="#{bean.image}">
<f:param name="filename" value="filename.ext" />
</p:graphicImage>
请注意示例 #{bean}
是 @ApplicationScoped
因为它基本上代表了无状态服务。也可以做@RequestScoped
,但随后该 bean 将会在每次请求时重新创建,而无需任何操作。你做不到 @ViewScoped
,因为此时浏览器需要下载图像,服务器不会创建 JSF 页面。你可以做到@SessionScoped
,但随后它会毫无意义地保存在内存中。
另请参阅:
- Recommended way to save uploaded files in a servlet application
- Simplest way to serve static data from outside the application server in a Java web application
- Abstract template for a static resource servlet (支持HTTP缓存)
- Show image as byte[] from database as graphic image in JSF page
- Display dynamic image from database with p:graphicImage and StreamedContent
- How to choose the right bean scope?
关于image - 使用 <h :graphicImage> or <img> tag 从 webapps/webcontext/deploy 文件夹外部加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4543936/