Самый простой способ обслуживания статических данных вне сервера приложений в веб-приложении 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.