Как сохранить файл на сервере (веб-контейнер) через веб-приложение Java EE?
Я разработал веб-приложение 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 ответа
Запись в файловую систему из контейнера Java EE не рекомендуется, особенно если вам нужно обработать записанные данные:
- это не транзакционный
- это вредит переносимости (что если вы находитесь в кластерной среде)
- требует настройки внешних параметров для целевого местоположения
Если это вариант, я бы сохранял файлы в базе данных или использовал JCR-репозиторий (например, Jackrabbit).
По спецификации, единственный "реальный" путь, который вы гарантированно получите из контейнера сервлета, - это временный каталог.
Вы можете получить это через ServletContext.gerAttribute("javax.servlet.context.tempdir")
, Однако эти файлы не видны веб-контексту (т. Е. Вы не можете опубликовать простой URL-адрес для доставки этих файлов), и эти файлы никоим образом не гарантируют выживание после перезапуска веб-приложения или сервера.
Если вам просто нужно место для хранения рабочего файла в течение короткого времени, то это будет хорошо работать для вас.
Если вам действительно нужен каталог, вы можете сделать его параметром конфигурации (либо переменная окружения, либо свойство Java (т.е. java -Dyour.file.here=/tmp/files ...
), параметр контекста, заданный в файле web.xml, параметр конфигурации, сохраненный в вашей базе данных через веб-форму и т. д.). Тогда это до развертывателя, чтобы настроить этот каталог для вас.
Тем не менее, если вам потребуется позднее обработать этот файл, вам потребуется механизм, специфичный для контейнера, для "монтирования" внешних каталогов в ваше веб-приложение (Glassfish как "альтернативные корни документов", другие имеют схожие концепции), или вы будете нужно написать сервлет / фильтр для обслуживания хранилища файлов за пределами вашего веб-приложения. Этот FileServlet довольно полон, и, как вы можете видеть, создание собственного, хотя и не сложного, совсем не тривиально, чтобы сделать это правильно.
Редактировать:
Основная суть та же, но вместо использования "getRealPath", просто используйте "getInitParameter".
Так:
String filePath = getServletContext().getInitParameter("storedFilePath") + "/" + fileName;
И быть на вашем пути.
Изменить еще раз:
Что касается содержимого пути, я бы дал ему абсолютный путь. В противном случае вам нужно ЗНАТЬ, где сервер приложений задает свой путь по умолчанию во время выполнения, и каждый сервер приложений вполне может использовать разные каталоги. Например, я считаю, что рабочий каталог для Glassfish является каталогом конфигурации работающего домена. Не особенно очевидный выбор.
Итак, используйте абсолютный путь, наиболее определенно. Таким образом, вы ЗНАЕТЕ, куда будут отправляться файлы, и можете контролировать права доступа на уровне ОС для этого каталога, если это необходимо.