Самый простой способ обслуживания статических данных вне сервера приложений в веб-приложении Java
У меня есть веб-приложение Java, используя Spring и Struts, работающие на Tomcat 5.5. Я хочу загрузить статические изображения, которые будут отображаться как в веб-интерфейсе, так и в файлах PDF, созданных приложением. Также новые изображения будут добавлены и сохранены путем загрузки через веб-интерфейс.
Это не проблема для этого, если статические данные хранятся в веб-контейнере, но хранение и загрузка их из-за границы веб-контейнера дает мне головную боль.
Я бы предпочел не использовать отдельный веб-сервер, например Apache, для обслуживания статических данных на данный момент. Мне также не нравится идея сохранения изображений в двоичном формате в базе данных.
Я видел некоторые предложения, например, что каталог изображений является символической ссылкой, указывающей на каталог вне веб-контейнера, но будет ли этот подход работать как в средах Windows, так и в * nix?
Некоторые предлагают писать фильтр или сервлет для обработки изображения, но эти предложения были очень неопределенными и высокоуровневыми, без указаний на более подробную информацию о том, как это сделать.
Ответы
Ответ 1
Я видел некоторые предложения, например, если каталог изображений является символической ссылкой, указывающей на каталог вне веб-контейнера, но будет ли этот подход работать как в средах Windows, так и в * nix?
Если вы придерживаетесь правил пути файловой системы * nix (т.е. используете исключительно косые черты в обратном направлении, как в /path/to/files
), то он также будет работать и на Windows, без необходимости скручиваться с уродливыми File.separator
строковыми конкатенациями. Однако он будет сканироваться только на том же рабочем диске, с которого была вызвана эта команда. Так что если Tomcat, например, установлен на C:
, тогда /path/to/files
на самом деле указывает на C:\path\to\files
.
Если все файлы находятся за пределами webapp, и вы хотите, чтобы Tomcat DefaultServlet
обрабатывал их, то все, что вам нужно сделать в Tomcat, - это добавить следующий элемент Context в /conf/server.xml
внутри <Host>
тег:
<Context docBase="/path/to/files" path="/files" />
Таким образом, они будут доступны через http://example.com/files/...
. Пример конфигурации GlassFish/Payara можно найти здесь и здесь приведен пример конфигурации WildFly здесь.
Если вы хотите иметь контроль над чтением/записью файлов самостоятельно, вам нужно создать Servlet
для этого, который в основном просто получает InputStream
файла в стиле, например FileInputStream
, и записывает его в OutputStream
HttpServletResponse
.
В ответ вам следует установить заголовок Content-Type
, чтобы клиент знал, какое приложение будет связываться с предоставленным файлом. И вы должны установить заголовок Content-Length
, чтобы клиент мог вычислить ход загрузки, иначе он будет неизвестен. И вы должны установить заголовок Content-Disposition
на attachment
, если вы хотите использовать диалоговое окно "Сохранить как", иначе клиент попытается отобразить его в строке. Наконец, просто напишите содержимое файла в выходной поток ответа.
Вот базовый пример такого сервлета:
@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());
}
}
При отображении на url-pattern
, например, /files/*
, вы можете называть его http://example.com/files/image.png
. Таким образом, вы можете получить больше контроля над запросами, чем это делает DefaultServlet
, например, предоставление изображения по умолчанию (т.е. if (!file.exists()) file = new File("/path/to/files", "404.gif")
или около того). Кроме того, использование request.getPathInfo()
предпочтительнее, чем request.getParameter()
, потому что оно более оптимистично для SEO, и в противном случае IE не будет выбирать правильное имя файла во время Save As.
Вы можете повторно использовать ту же логику для обслуживания файлов из базы данных. Просто замените new FileInputStream()
на ResultSet#getInputStream()
.
Надеюсь, что это поможет.
См. также:
Ответ 2
Вы можете сделать это, поместив ваши изображения на фиксированный путь (например:/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 будет <img src="imageServlet?imageName=myimage.png" />
Конечно, вы должны думать о обслуживании разных типов контента - "image/jpeg", например, на основе расширения файла. Также вы должны предоставить некоторое кэширование.
Кроме того, вы можете использовать этот сервлет для качественного масштабирования ваших изображений, предоставляя параметры ширины и высоты в качестве аргументов и используя image.getScaledInstance(w, h, Image.SCALE_SMOOTH
), учитывая, конечно, производительность.
Ответ 3
Требование: доступ к статическим ресурсам (изображения/видео и т.д.) извне каталога WEBROOT или с локального диска
Шаг 1:
Создайте папку под webapps сервера tomcat. Скажем, имя папки myproj
Шаг 2:
Под myproj создайте папку WEB-INF под этим создаем простой web.xml
код под web.xml
<web-app>
</web-app>
Структура каталога для двух предыдущих шагов
c:\programfile\apachesoftwarefoundation\tomcat\...\webapps
|
|---myproj
| |
| |---WEB-INF
| |
|---web.xml
Шаг 3:
Теперь создайте xml файл с именем myproj.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" />
Шаг 4:
4 A) Теперь создайте папку с именем myproj в диске E вашего жесткого диска и создайте новый
с изображениями имен и поместите некоторые изображения в папку с изображениями (e:myproj\images\)
Предположим, что myfoto.jpg находится под e:\myproj\images\myfoto.jpg
4 B) Теперь создайте папку с именем WEB-INF в e:\myproj\WEB-INF
и создайте web.xml в папке WEB-INF
Код в web.xml
<web-app>
</web-app>
Шаг 5:
Теперь создайте документ .html с именем index.html и поместите в e:\myproj
КОД под индексом index.html Добро пожаловать в Myproj
Структура каталогов для вышеуказанных шагов 4 и 5 выглядит следующим образом
E:\myproj
|--index.html
|
|--images
| |----myfoto.jpg
|
|--WEB-INF
| |--web.xml
Шаг 6:
Теперь запустите сервер Tomcat Apache
Шаг 7: Откройте браузер и введите URL-адрес следующим образом
http://localhost:8080/myproj
тогда u отображает содержимое, которое предоставляется в index.html
Шаг 8:
Доступ к изображениям под локальным жестким диском (за пределами веб-сайта)
http://localhost:8080/myproj/images/myfoto.jpg
Ответ 4
Добавить в server.xml:
<Context docBase="c:/dirtoshare" path="/dir" />
Включить параметр списка файлов dir в файле web.xml:
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
Ответ 5
Это история с моего рабочего места:
- Мы пытаемся загрузить многократные изображения и файлы документов, используя Struts 1 и Tomcat 7.x.
- Мы пытаемся записать загруженные файлы в файловую систему, имя файла и полный путь к записям базы данных.
- Мы стараемся разделять папки с файлами вне каталога веб-приложений. (*)
Нижеприведенное решение довольно просто, эффективно для требования (*):
В файле META-INF/context.xml
со следующим содержимым:
(Например, мое приложение работает в http://localhost:8080/ABC
, мое приложение/проект с именем ABC
).
(это также полное содержимое файла context.xml
)
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>
(работает с Tomcat версии 7 или новее)
Результат: Мы создали 2 псевдонима. Например, мы сохраняем изображения по адресу: D:\images\foo.jpg
и просмотр из ссылки или с помощью тега изображения:
<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">
(Я использую Netbeans 7.x, Netbeans кажется автоматически созданным файлом WEB-INF\context.xml
)
Ответ 6
Если вы решите отправить на FileServlet
, вам также понадобится allowLinking="true"
в context.xml
, чтобы позволить FileServlet
пересекать символические ссылки.
См. http://tomcat.apache.org/tomcat-6.0-doc/config/context.html
Ответ 7
Я сделал это еще проще. Проблема. В файле CSS были ссылки на URL-адрес папки img. Получает 404.
Я посмотрел url, http://tomcatfolder:port/img/blablah.png, которого не существует. Но это действительно указывает на приложение ROOT в Tomcat.
Итак, я просто скопировал папку img из моего webapp в это приложение ROOT. Работает!
Не рекомендуется для производства, конечно, но это для внутреннего инструмента для разработки инструментов.
Ответ 8
если кто-либо не сможет решить свою проблему с принятым ответом, тогда обратите внимание на следующие соображения:
- Не нужно упоминать
localhost:<port>
с атрибутом <img> src
.
- убедитесь, что вы запускаете этот проект за пределами eclipse, потому что eclipse создает запись
context docBase
самостоятельно внутри своего локального файла server.xml
.