Как сохранить файл на сервере (веб-контейнер) через веб-приложение Java EE? - PullRequest
11 голосов
/ 18 апреля 2010

Я разработал веб-приложение Java EE. Это приложение позволяет пользователю загружать файл с помощью браузера. Как только пользователь загрузил свой файл, это приложение сначала сохраняет загруженный файл на сервере (на котором он запущен), а затем обрабатывает его.

В настоящее время я храню файл на сервере следующим образом:

try {
    // formFile represents the uploaded file
    FormFile formFile = programForm.getTheFile();
    String path = getServlet().getServletContext().getRealPath("") + "/"
        + formFile.getFileName();
    System.out.println(path);
    file = new File(path);
    outputStream = new FileOutputStream(file);
    outputStream.write(formFile.getFileData());
}

где formFile представляет загруженный файл.

Теперь проблема в том, что на некоторых серверах он работает нормально, но на некоторых серверах getServlet().getServletContext().getRealPath("") возвращает null, поэтому последний путь, который я получаю, - null/filename, и файл не сохраняется на сервер.

Когда я проверил API для метода ServletContext.getRealPath(), я обнаружил следующее:

public java.lang.String getRealPath(java.lang.String path)

Возвращает строку, содержащую реальный путь для данного виртуального пути. Например, путь "/index.html" возвращает абсолютный путь к файлу в файловой системе сервера, который будет обслуживаться запросом для "http://host/contextPath/index.html", где contextPath - это контекстный путь этого ServletContext.

Реальный путь будет возвращен в форме, соответствующей компьютеру и операционной системе, в которой работает контейнер сервлета, включая надлежащие разделители пути. Этот метод возвращает значение null, если контейнер сервлета по какой-либо причине не может преобразовать виртуальный путь в реальный путь (например, когда содержимое становится доступным из архива .war).

Итак, есть ли другой способ, с помощью которого я могу хранить файлы на этих серверах, который возвращает null для getServlet().getServletContext().getRealPath("")

Ответы [ 2 ]

20 голосов
/ 18 апреля 2010

По спецификации, единственный "реальный" путь, который вы гарантированно получите из контейнера сервлета, - это временный каталог.

Вы можете получить это через ServletContext.gerAttribute("javax.servlet.context.tempdir"). Однако эти файлы не видны веб-контексту (т. Е. Вы не можете опубликовать простой URL-адрес для доставки этих файлов), и эти файлы никоим образом не гарантируют выживание при перезапуске веб-приложения или сервера.

Если вам просто нужно место для хранения рабочего файла в течение короткого времени, тогда это будет хорошо для вас.

Если вам действительно нужен каталог, вы можете сделать его параметром конфигурации (либо переменной среды, либо свойством Java (т. Е. java -Dyour.file.here=/tmp/files ...), параметром контекста, заданным в web.xml, параметром конфигурации, хранящимся в вашей базе данных. через веб-форму и т. д.). Затем вам нужно установить этот каталог для развертывателя.

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

Edit:

Основная суть та же, но вместо использования "getRealPath", просто используйте "getInitParameter".

Итак:

String filePath = getServletContext().getInitParameter("storedFilePath") + "/" + fileName;

И уже в пути.

Редактировать еще раз:

Что касается содержимого пути, я бы дал ему абсолютный путь. В противном случае вам нужно ЗНАТЬ, где сервер приложений задает свой путь по умолчанию во время выполнения, и каждый сервер приложений вполне может использовать разные каталоги. Например, я считаю, что рабочий каталог для Glassfish является каталогом конфигурации работающего домена. Не особенно очевидный выбор.

Итак, используйте абсолютный путь, наиболее определенно. Таким образом, вы ЗНАЕТЕ, куда будут отправляться файлы, и можете контролировать права доступа на уровне ОС для этого каталога, если это необходимо.

13 голосов
/ 19 апреля 2010

Запись в файловую систему из контейнера Java EE не рекомендуется, особенно если вам нужно обработать записанные данные:

  • это не транзакция
  • это вредит переносимости (что если вы находитесь в кластерной среде)
  • требуется настроить внешние параметры для целевого местоположения

Если это вариант, я буду хранить файлы в базе данных или использовать JCR-репозиторий (например, Jackrabbit ).

...