Загружать изображения из папки webapps/webcontext/deploy с помощью тега <h: graphicImage> или <img>

Мне нужно отображать изображения, которые находятся за пределами папки развертывания в веб-приложении, используя тег JSF <h:graphicimage> или тег HTML <img>. Как я могу это достичь?

Ответ 1

Кстати, он должен быть доступен по общедоступному URL. Таким образом, <img src> должен в конечном итоге ссылаться на http:// URI, а не на что-то вроде file:// URI или около того. В конечном счете, исходный код HTML выполняется на компьютере конечного пользователя, и изображения загружаются веб-браузером индивидуально во время анализа исходного кода HTML. Когда веб-браузер обнаруживает URI file:// такой как C:\path\to\image.png, он ищет в файловой системе локального диска конечного пользователя изображение вместо веб-сервера. Это, очевидно, не сработает, если веб-браузер работает на физически другой машине, чем веб-сервер.

Есть несколько способов добиться этого:

  1. Если у вас есть полный контроль над папкой с изображениями, просто перетащите папку со всеми изображениями, например, https://stackoverflow.com/images непосредственно в папку развертывания servletcontainer, например, папку /webapps в случае Tomcat и папку /domains/domain1/applications в случае GlassFish, Никаких дополнительных настроек не требуется.


  2. Или добавьте новый контекст веб-приложения на сервер, который указывает на абсолютное расположение файловой системы диска в папке с этими изображениями. Как это сделать, зависит от используемого контейнера. В приведенных ниже примерах предполагается, что изображения находятся в /path/tohttps://stackoverflow.com/images и что вы хотите получить к ним доступ через http://...https://stackoverflow.com/images.

    В случае Tomcat добавьте следующую новую запись в Tomcat /conf/server.xml внутри <Host>:

    <Context docBase="/path/tohttps://stackoverflow.com/images" path="https://stackoverflow.com/images" />
    

    В случае GlassFish добавьте следующую запись в /WEB-INF/glassfish-web.xml:

    <property name="alternatedocroot_1" value="from=https://stackoverflow.com/images/* dir=/path/to" />
    

    В случае WildFly добавьте следующую запись в <host name="default-host"> /standalone/configuration/standalone.xml...

    <location name="https://stackoverflow.com/images" handler="images-content" />
    

    ... и далее в <handlers> той же <subsystem> что и выше <location>:

    <file name="images-content" path="/path/tohttps://stackoverflow.com/images" />
    

  3. Или создайте Servlet который передает изображение с диска в ответ:

    @WebServlet("https://stackoverflow.com/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/tohttps://stackoverflow.com/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 может быть полезен, так как он также учитывает запросы заголовка, кэширования и диапазона.


  4. Или используйте OmniFaces <o:graphicImage> который поддерживает свойство компонента, возвращающее byte[] или InputStream:

    @Named
    @ApplicationScoped
    public class Bean {
    
        public InputStream getImage(String filename) {
            return new FileInputStream(new File("/path/tohttps://stackoverflow.com/images", filename));
        }
    }
    

  5. Или используйте PrimeFaces <p:graphicImage>, который поддерживает метод боба возвращающийся PrimeFaces специфичного 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/tohttps://stackoverflow.com/images", filename)));
            }
        }
    }
    

Для первого способа, а для Tomcat и WildFly - вторым, изображения будут доступны по адресу http://example.comhttps://stackoverflow.com/images/filename.ext и, таким образом, будут ссылаться в обычном HTML следующим образом

<img src="https://stackoverflow.com/images/filename.ext" />

Для подхода GlassFish вторым и третьим способами изображения будут доступны по адресу http://example.com/contexthttps://stackoverflow.com/images/filename.ext и, таким образом, будут ссылаться в обычном HTML следующим образом

<img src="#{request.contextPath}https://stackoverflow.com/images/filename.ext" />

или в JSF следующим образом (автоматически добавляется контекстный путь)

<h:graphicImage value="https://stackoverflow.com/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, но тогда бин будет воссоздан при каждом отдельном запросе, даром. Вы не можете сделать это @ViewScoped, потому что в настоящее время браузер должен загрузить изображение, сервер не создает страницу JSF. Вы можете сделать это @SessionScoped, но затем он будет сохранен в памяти, даром.

Смотрите также:

Ответ 2

Чтобы добиться того, что вам нужно, используя теги <h:graphicImage> или <img>, вам необходимо создать псевдоним Tomcat v7, чтобы сопоставить внешний путь с контекстом вашего веб-приложения.

Для этого вам нужно указать контекст веб-приложения. Самый простой способ - определить файл META-INF/context.xml со следующим содержимым:

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

Затем после перезагрузки сервера Tomcat вы можете получить доступ к своим файлам изображений с помощью тегов <h:graphicImage > или <img> следующим образом:

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

или

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

* Обратите внимание, что путь для контекста необходим для тега, но не для


Другой возможный подход, если вы не хотите, чтобы изображения были доступны через HTTP GET-метод, может заключаться в использовании Primefaces <p:fileDownload> tag (используя теги commandLink или commandButton - метод 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 вы можете реализовать свой компонент следующим образом:

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>

Я предлагаю установить атрибут cache = "false" в компоненте graphicImage.

Ответ 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.Base64, java.nio.file.Paths и java.nio.file.Files.