Простейший способ обслуживания статических данных извне сервера приложений в веб-приложении Java
У меня есть веб-приложение Java, работающее на Tomcat. Я хочу загрузить статические изображения, которые будут отображаться как в веб-интерфейсе, так и в файлах PDF, сгенерированных приложением. Также новые изображения будут добавлены и сохранены путем загрузки через веб-интерфейс.
Это не проблема сделать, храня статические данные внутри веб-контейнера, но хранение и загрузка их извне веб-контейнера вызывает у меня головную боль.
На данном этапе я бы предпочел не использовать отдельный веб-сервер, такой как Apache, для обслуживания статических данных. Мне также не нравится идея хранения изображений в двоичном формате в базе данных.
Я видел несколько предложений, например, чтобы каталог изображений был символической ссылкой, указывающей на каталог вне веб-контейнера, но будет ли этот подход работать как в средах Windows, так и * nix?
Некоторые предлагают написать фильтр или сервлет для обработки подачи изображений, но эти предложения были очень расплывчатыми и высокоуровневыми, без указателей на более подробную информацию о том, как это сделать.
Переведено автоматически
Ответ 1
Я видел несколько предложений, например, чтобы каталог изображений был символической ссылкой, указывающей на каталог вне веб-контейнера, но будет ли этот подход работать как в средах Windows, так и * nix?
Если вы придерживаетесь правил пути к файловой системе * nix (т. Е. Используете исключительно косые черты, как в /path/to/files
), то он будет работать и в Windows без необходимости возиться с уродливыми File.separator
конкатенациями строк. Однако они будут сканироваться только на том же рабочем диске, с которого была вызвана эта команда. Итак, если Tomcat, например, установлен на C:
, то /path/to/files
фактически будет указывать на C:\path\to\files
.
Если все файлы расположены вне веб-приложения, и вы хотите, чтобы Tomcat DefaultServlet
обрабатывал их, то все, что вам в принципе нужно сделать в Tomcat, это добавить следующий элемент контекста в тег /conf/server.xml
inside <Host>
:
<Context docBase="/path/to/files" path="/files" />
Таким образом, они будут доступны через http://example.com/files/...
. Для серверов на базе Tomcat, таких как JBoss EAP 6.x или более поздней версии, подход в основном тот же, смотрите также Здесь. Пример конфигурации 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
of /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 не выберет правильное имя файла во время сохранения как.
Вы можете повторно использовать ту же логику для обслуживания файлов из базы данных. Просто замените new FileInputStream()
на ResultSet#getInputStream()
.
Смотрите также:
- Рекомендуемый способ сохранения загруженных файлов в приложении-сервлете
- Абстрактный шаблон для сервлета статических ресурсов (поддерживающий HTTP-кэш)
- Как извлекать и отображать изображения из базы данных на странице JSP?
- Как передавать аудио / видео файлы, такие как MP3, MP4, AVI и т.д., с помощью сервлета
Ответ 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" />
Конечно, вам следует подумать об обслуживании различных типов контента - "изображение / 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 вашего жесткого диска и создайте новую
назовите папку images и поместите некоторые изображения в папку images (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>
Step 5:
Now create a .html document with name index.html and place under e:\myproj
CODE under index.html
Welcome to Myproj
The Directory Structure for the above Step 4 and Step 5 is as follows
E:\myproj
|--index.html
|
|--images
| |----myfoto.jpg
|
|--WEB-INF
| |--web.xml
Step 6:
Now start the apache tomcat server
Step 7:
open the browser and type the url as follows
http://localhost:8080/myproj
затем вы отображаете содержимое, которое предоставляется в index.html
Шаг 8:
Для доступа к изображениям на вашем локальном жестком диске (за пределами webroot)
http://localhost:8080/myproj/images/myfoto.jpg
Ответ 4
Добавить в server.xml :
<Context docBase="c:/dirtoshare" path="/dir" />
Включить параметр dir file listing в web.xml :
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>