使用 <h:graphicImage> 或 <img> 标签从 webapps / webcontext / deploy 文件夹外部加载图像

Posted

技术标签:

【中文标题】使用 <h:graphicImage> 或 <img> 标签从 webapps / webcontext / deploy 文件夹外部加载图像【英文标题】:Load images from outside of webapps / webcontext / deploy folder using <h:graphicImage> or <img> tag 【发布时间】:2011-05-31 10:41:21 【问题描述】:

我需要使用 JSF &lt;h:graphicimage&gt; 标记或 html &lt;img&gt; 标记显示驻留在 Web 应用程序中部署文件夹之外的图像。我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

重要的是,它必须可以通过公共 URL 访问。因此,&lt;img src&gt; 最终必须引用 http:// URI,而不是 file:// URI 左右。最终,HTML 源代码在最终用户的机器上执行,并且图像在解析 HTML 源代码期间由网络浏览器单独下载。当网络浏览器遇到file:// URI 例如C:\path\to\image.png 时,它将在最终用户自己的本地磁盘文件系统中查找图像,而不是在网络服务器的文件系统中查找。如果网络浏览器在物理上与网络服务器不同的机器上运行,这显然是行不通的。

有几种方法可以实现这一点:

    如果您可以完全控制图像文件夹,则只需删除包含所有图像的文件夹,例如/images 直接在 servletcontainer 的 deploy 文件夹中,例如 Tomcat 的 /webapps 文件夹和 GlassFish 的 /domains/domain1/applications 文件夹。无需进一步配置。


    或者,向服务器添加一个新的 webapp 上下文,该上下文指向包含这些图像的文件夹的绝对磁盘文件系统位置。如何做到这一点取决于使用的容器。下面的示例假设图像位于/path/to/images,并且您希望通过http://.../images 访问它们。

    如果是 Tomcat,将以下新条目添加到 Tomcat 的 /conf/server.xml 内的 &lt;Host&gt;

    <Context docBase="/path/to/images" path="/images" />
    

    如果是 GlassFish,请将以下条目添加到 /WEB-INF/glassfish-web.xml

    <property name="alternatedocroot_1" value="from=/images/* dir=/path/to" />
    

    如果是 WildFly,请在 &lt;host name="default-host"&gt; of /standalone/configuration/standalone.xml 中添加以下条目 ...

    <location name="/images" handler="images-content" />
    

    ...在&lt;handlers&gt; 的下方,与上面&lt;location&gt; 完全相同的&lt;subsystem&gt; 条目:

    <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 可能会很有用,因为它还考虑了头部、缓存和范围请求。


    或者,使用支持返回byte[]InputStream 的bean 属性的OmniFaces &lt;o:graphicImage&gt;

    @Named
    @ApplicationScoped
    public class Bean 
    
        public InputStream getImage(String filename) 
            return new FileInputStream(new File("/path/to/images", filename));
        
    
    

    或者,使用 PrimeFaces &lt;p:graphicImage&gt;,它支持返回 PrimeFaces 特定 StreamedContent 的 bean 方法。

    @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?

【讨论】:

嗨 BalusC,感谢您的快速回复。如果我在 linux 中使用它,我的图像的绝对路径是 /home/muneeswaran/apache-tomcat-6.0.29/headers/Aboutus/images/ ss.jpg.SO 我可以在 server.xml 中将上下文存储为 吗? 是的,那么您可以通过example.com/images/Aboutus/images/ss.jpg 访问它。但是,既然您似乎可以完全控制它(您已将它放在 Tomcat 安装文件夹中!),为什么不将它放在 /webapps 文件夹中呢?然后你不需要添加另一个上下文。 嗨 BalusC,我们已经使用 servlet 使用了一个名为 emsd 的上下文,我可以使用另一个名为 images 的上下文吗?如果我根据您的建议通过工作使用它,它会将这个上下文作为子上下文esmd。所以我无法使用 访问图像。我该怎么做? 是的,你可以。以同样的方式访问它。 @Harry:在 asadmin 或 sun-web.xml 中创建一个虚拟目录。 marceble.com/2009/07/virtual-directories-in-glassfish【参考方案2】:

为了使用&lt;h:graphicImage&gt;&lt;img&gt; 标签实现您的需要,您需要创建一个Tomcat v7 别名,以便将外部路径映射到您的Web 应用程序的上下文。

为此,您需要specify your web app's context。最简单的方法是定义一个 META-INF/context.xml 文件,其内容如下:

<Context path="/myapp" aliases="/images=/path/to/external/images">
</Context>

然后重启你的Tomcat服务器后,你可以使用&lt;h:graphicImage>或者&lt;img&gt;标签访问你的图片文件,如下:

<h:graphicImage value="/images/my-image.png">

<img src="/myapp/images/my-image.png">

*注意上下文路径对于标签是必需的,而不是对于


如果您不要求图像通过 HTTP GET 方法可用,另一种可能的方法是使用 Primefaces &lt;p:fileDownload&gt; 标签(使用 commandLinkcommandButton标签 - HTTP POST 方法)。

在你的 Facelet 中:

<h:form>
  <h:commandLink id="downloadLink" value="Download">  
    <p:fileDownload value="#fileDownloader.getStream(file.path)" />  
</h:commandLink>
</h:form

在你的 bean 中:

@ManagedBean
@ApplicationScope
public class FileDownloader 

    public StreamedContent getStream(String absPath) throws Exception 
        FileInputStream fis = new FileInputStream(absPath);
        BufferedInputStream bis = new BufferedInputStream(fis);
        StreamedContent content = new DefaultStreamedContent(bis);
        return content;
       
    

【讨论】:

【参考方案3】:

在 PrimeFaces 中,您可以通过这种方式实现您的 bean:

private StreamedContent image;

public void setImage(StreamedContent image) 
    this.image = image;


public StreamedContent getImage() throws Exception 
    return image;


public void prepImage() throws Exception 
File file = new File("/path/to/your/image.png");
InputStream input = new FileInputStream(file);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
setImage(new DefaultStreamedContent(input,externalContext.getMimeType(file.getName()), file.getName()));

在您的 HTML Facelet 中:

<body onload="#yourBean.prepImage()"></body> 
<p:graphicImage value="#youyBean.image" style="width:100%;height:100%" cache="false" >
</p:graphicImage>

我建议在graphicImage组件中设置属性cache="false"。

【讨论】:

【参考方案4】:

在 JSP 中

<img src="data:image/jpeg;base64,
<%= new String(Base64.encode(Files.readAllBytes(Paths.get("C:\\temp\\A.jpg"))))%>"/>

包是com.sun.jersey.core.util.Base64java.nio.file.Pathsjava.nio.file.Files

【讨论】:

我们不会在 JSF 而不是 JSP 中 这在 JSF 中怎么可能?

以上是关于使用 <h:graphicImage> 或 <img> 标签从 webapps / webcontext / deploy 文件夹外部加载图像的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 h:graphicImage JSF 2.0 显示图像

如果组合组件为空,如何不设置组件内部的属性?

在不使用过滤器和包装器的情况下删除 URL 中的 JSESSIONID

<q>、<blockquote> 和 <cite> 的有效使用

如何使用js 删除<ul>下第一个<li>

何时使用 Mono<List<Object>> 以及何时使用 Flux<Object> 用于 RestController 方法