Мне нужно отображать изображения, которые находятся за пределами папки развертывания в веб-приложении, используя тег JSF <h:graphicimage>
или тег HTML <img>
. Как я могу это достичь?
Загружать изображения из папки webapps/webcontext/deploy с помощью тега <h: graphicImage> или <img>
Ответ 1
Кстати, он должен быть доступен по общедоступному URL. Таким образом, <img src>
должен в конечном итоге ссылаться на http://
URI, а не на что-то вроде file://
URI или около того. В конечном счете, исходный код HTML выполняется на компьютере конечного пользователя, и изображения загружаются веб-браузером индивидуально во время анализа исходного кода HTML. Когда веб-браузер обнаруживает URI file://
такой как C:\path\to\image.png
, он ищет в файловой системе локального диска конечного пользователя изображение вместо веб-сервера. Это, очевидно, не сработает, если веб-браузер работает на физически другой машине, чем веб-сервер.
Есть несколько способов добиться этого:
-
Если у вас есть полный контроль над папкой с изображениями, просто перетащите папку со всеми изображениями, например,
https://stackoverflow.com/images
непосредственно в папку развертывания servletcontainer, например, папку/webapps
в случае Tomcat и папку/domains/domain1/applications
в случае GlassFish, Никаких дополнительных настроек не требуется. -
Или добавьте новый контекст веб-приложения на сервер, который указывает на абсолютное расположение файловой системы диска в папке с этими изображениями. Как это сделать, зависит от используемого контейнера. В приведенных ниже примерах предполагается, что изображения находятся в
/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" />
-
Или создайте
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
может быть полезен, так как он также учитывает запросы заголовка, кэширования и диапазона. -
Или используйте 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)); } }
-
Или используйте 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
, но затем он будет сохранен в памяти, даром.
Смотрите также:
- Рекомендуемый способ сохранения загруженных файлов в приложении сервлета
- Самый простой способ обслуживания статических данных извне сервера приложений в веб-приложении Java
- Абстрактный шаблон для сервлета статических ресурсов (с поддержкой HTTP-кэширования)
- Показывать изображение как байт [] из базы данных как графическое изображение на странице JSF
- Отображение динамического изображения из базы данных с помощью p: graphicImage и StreamedContent
- Как правильно выбрать сферу применения бобов?
Ответ 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
.