Загрузка изображения Java/JSP. Где хранить эти файлы изображений?

Я пишу простое приложение, которое позволяет пользователю загружать изображения. После загрузки пользователь может их пометить или удалить.

Я выяснил, как загружать файлы и сохранять их после загрузки файлов. Я отслеживаю глобальный путь хранения изображений. В базе данных я сохраняю метаданные об изображениях, таких как имя файла, теги и т.д.

Я использую Java/JSP (в частности, структуру Stripes, но моя проблема является общей).

Мой вопрос в том, где я могу хранить эти файлы изображений после их загрузки?

Сейчас у меня есть два веб-приложения, развернутые на сервере Tomcat. Одно основное веб-приложение и другое - это то, где я загружаю изображения.

Но это не работает, поскольку я не вижу загруженные изображения в основном приложении до тех пор, пока не переустанавливаю и не перезагружаю Tomcat.

Кажется, что Tomcat автоматически не выбирает новые загруженные изображения.

Есть ли у кого-нибудь какие-либо решения?

Это простой проект, поэтому я не хочу хранить их в базе данных или использовать Apache для изображений. Это слишком сложно для этого небольшого проекта.

Спасибо.

6 ответов

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Image streaming Servlet.
 */
public class ImageDisplayServlet extends HttpServlet {
 private static final long serialVersionUID = 1L;
 /**
 * @see HttpServlet#HttpServlet()
 */
 public ImageDisplayServlet() {
 super();
 }
 /**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 String relativePath = trimToEmpty(request.getPathInfo());
 // Make sure no one try to screw with us. 
 // This is important as user can literally access any file if we are not careful
 if(isXSSAttack(relativePath) == false) {
 String pathToFile = this.getServletContext().getRealPath(request.getPathInfo());
 File file = new File(pathToFile);
 System.out.println("Looking for file " + file.getAbsolutePath());
 // show a 404 page
 if(!file.exists() || !file.isFile()) {
 httpError(404, response);
 } else {
 try {
 streamImageFile(file, response);
 } catch(Exception e) {
 // Tell the user there was some internal server error.\
 // 500 - Internal server error.
 httpError(500, response);
 e.printStackTrace();
 }
 }
 } else {
 // what to do if i think it is a XSS attack ?!?
 }
 }
 private void streamImageFile(File file, HttpServletResponse response) {
 // find the right MIME type and set it as content type
 response.setContentType(getContentType(file));
 BufferedInputStream bis = null;
 BufferedOutputStream bos = null;
 try {
 response.setContentLength((int) file.length());
 // Use Buffered Stream for reading/writing.
 bis = new BufferedInputStream(new FileInputStream(file));
 bos = new BufferedOutputStream(response.getOutputStream());
 byte[] buff = new byte[(int) file.length()];
 int bytesRead;
 // Simple read/write loop.
 while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
 bos.write(buff, 0, bytesRead);
 }
 } catch (Exception e) {
 throw new RuntimeException(e);
 } finally {
 if (bis != null) {
 try {
 bis.close();
 } catch (IOException e) {
 e.printStackTrace();
 // To late to do anything about it now, we may have already sent some data to user.
 }
 }
 if (bos != null) {
 try {
 bos.close();
 } catch (IOException e) {
 e.printStackTrace();
 // To late to do anything about it now, we may have already sent some data to user.
 }
 }
 } 
 }
 private String getContentType(File file) {
 if(file.getName().length() > 0) {
 String[] parts = file.getName().split("\\.");
 if(parts.length > 0) {
 // only last part interests me
 String extention = parts[parts.length - 1];
 if(extention.equalsIgnoreCase("jpg")) {
 return "image/jpg";
 } else if(extention.equalsIgnoreCase("gif")) {
 return "image/gif"; 
 } else if(extention.equalsIgnoreCase("png")) {
 return "image/png";
 }
 }
 }
 throw new RuntimeException("Can not find content type for the file " + file.getAbsolutePath());
 }
 private String trimToEmpty(String pathInfo) {
 if(pathInfo == null) {
 return "";
 } else {
 return pathInfo.trim();
 }
 }
 private void httpError(int statusCode, HttpServletResponse response) {
 try {
 response.setStatus(statusCode);
 response.setContentType("text/html");
 PrintWriter writer = response.getWriter();
 writer.append("<h1>Error Code: " + statusCode + "</h1>");
 writer.flush();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 private boolean isXSSAttack(String path) {
 boolean xss = false;
 // Split on the bases of know file separator
 String[] parts = path.split("/|\\\\");
 // Now verify that no part contains anything harmful
 for(String part : parts) {
 // No ****** dots .. 
 // No colons :
 // No semicolons ;
 if(part.trim().contains("..") || part.trim().contains(":") || part.trim().contains(";")) {
 // Fire in the hole!
 xss = true;
 break;
 }
 }
 return xss;
 }
 /**
 * @see HttpServlet#doPost(Ht/promotions/some.jpgtpServletRequest request, HttpServletResponse response)
 */
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 doGet(request, response);
 }
}

Ok Вот сервлет, который я быстро написал, который может передавать изображения:

Вот список ограничений и проблем с информацией:

  • Может быть уязвимость XSS с осторожностью
  • Не готовность производства в качестве ссылки
  • Изображения должны находиться в каталоге веб-приложения. Можно легко изменить, но я слишком ленив (это не стоит слишком мало для проекта)
  • Загружать только файлы jpg, gif или png.

Применение:

Скажем, вы разворачиваете это веб-приложение под названием изображения как отдельное приложение.

http://www.example.com/images/promotions/promo.jpg

означает, что в этом веб-приложении изображений должен быть каталог в "рекламных акциях" с изображением "promo.jpg".

PS: Не спрашивайте, почему я делаю это решение только для Servlet Container, которое засасывает большое время.


<servlet>
 
 <display-name>ImageDisplayServlet</display-name>
 <servlet-name>ImageDisplayServlet</servlet-name>
 <servlet-class>com.example.images.ImageDisplayServlet</servlet-class>
 </servlet>
 <servlet-mapping>
 <servlet-name>ImageDisplayServlet</servlet-name>
 <url-pattern>/*</url-pattern>
 </servlet-mapping>

О, вы можете настроить свой сервлет, как указано выше, для получения наилучших результатов: P


Определенно не сохраняйте изображения в базе данных, но вы хотите сохранить путь изображения в базе данных. Это позволит вам сохранить изображение где угодно.

Поскольку вы используете два приложения tomcat, лучшим вариантом может быть сохранение изображений за пределами любого приложения и передача изображения обратно пользователю вместо того, чтобы позволить tomcat управлять файлами. В противном случае я бы спросил, почему вы пытаетесь сделать это с помощью двух веб-приложений.


Однако сохранение загруженных изображений внутри каталога веб-приложений не является разумным делом, и вы это знаете.

Кстати, вы можете посмотреть этот qaru.site/questions/7373/..., в последнее время обсуждали, где хранить изображения. Это может не решить вашу проблему, несомненно, даст вам больше уверенности в том, что вы делаете.


Я решил это по-разному.

Во-первых, непереносимый способ заключается в том, что Glassfish (и я тоже верю Tomcat) позволяет сопоставить внешний каталог с иерархией webapps. Это работает очень хорошо и делает именно то, что вы хотите. Он позволяет хранить ваши изображения во внешнем каталоге вдали от вашего веб-приложения, но все равно обслуживать их.

Однако этот метод не переносится.

Способ сделать это переносимым образом - это создать фильтр.

Вы помещаете фильтр в какое-то место, например "/images".

Что делает фильтр:

  • он проверяет, что изображение (или что-либо, оно работает с любым статическим ресурсом) в специальном каталоге внутри webapp. В нашем примере мы будем использовать url/webapp/images.

  • если файл НЕ существует, мы скопируем файл из вашего внешнего местоположения в соответствующее место в webapp. Итак, скажем, reqyest url - "/images/banner.gif". И ваши файлы хранятся на диске в папке "/home/app/images". Итак, наш исходный файл - "/home/app/images/banner.gif". Затем мы копируем его туда, где мы хотим его в дереве webapp. Для этого мы используем "ServletContext.getRealPath". Таким образом, местом назначения будет "ServletContext.get RealPath" ( "/webapp/images/banner.gif" ). Просто скопируйте источник в пункт назначения.

  • Если файл уже существует или существует, просто перейдите к фактическому изображению в /webapp/images/banner.gif.

Фактически вы получаете кеш файл в своем дереве развертывания webapps. Нижняя сторона - это кеш, поэтому его необходимо поддерживать (т.е. Вы должны проверить, является ли оригинал более новым, чем ваш кеш, убедитесь, что вы удаляете, если источник удален и т.д.). Кроме того, он дублирует ваши ресурсы, поэтому ваши изображения будут потреблять, в конечном счете, вдвое больше дискового пространства. Наконец, начальная стоимость копирования при запуске.

Однако он работает, и это мешает вам обслуживать статические ресурсы, используя свой собственный код. (Это 3-е решение, сопоставьте фильтр/сервлет, чтобы перехватить URL-адреса и просто передать его себе.)

Я бы посмотрел на конструкцию внутри Tomcat (при условии, что она существует), чтобы сделать сопоставление для вас. Я знаю, что он существует в Glassfish. (Google alternatedocroot для Glassfish, чтобы увидеть, как это работает.)


Я использовал два веб-приложения, чтобы избежать написания загруженных изображений в случае, если я переустановил новый главный файл войны приложения.

Но, как вы говорите, нет другого выбора, кроме как передать их через сервлет или что-то, что, я думаю, я могу оставить их вне каталога tomcat.

Я хотел избежать написания этого потокового сервлета. Это слишком маленький проект для работы со всеми беспорядками (например, правильный тип контента, 404 и т.д.) При написании потокового сервлета.

licensed under cc by-sa 3.0 with attribution.