1. Обзор
Общей особенностью веб-приложений является возможность загрузки файлов.
В этом руководстве мы рассмотрим простой пример создания загружаемого файла и его обслуживания из приложения Java Servlet .
Используемый нами файл будет из ресурсов веб-приложения.
2. Зависимости Maven
При использовании Jakarta EE нам не нужно будет добавлять какие-либо зависимости. Однако, если мы используем Java SE, нам понадобится зависимость javax.servlet-api:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
Последнюю версию зависимости можно найти здесь .
3. Сервлет
Давайте сначала посмотрим на код, а затем выясним, что происходит:
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
private final int ARBITARY_SIZE = 1048;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.setHeader("Content-disposition", "attachment; filename=sample.txt");
try(InputStream in = req.getServletContext().getResourceAsStream("/WEB-INF/sample.txt");
OutputStream out = resp.getOutputStream()) {
byte[] buffer = new byte[ARBITARY_SIZE];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
}
}
}
3.1. Запросить конечную точку
Аннотация @WebServlet («/download»)
помечает класс DownloadServlet
для обслуживания запросов, направленных на конечную точку «/download» .
В качестве альтернативы мы можем сделать это, описав сопоставление в файле web.xml.
3.2. Тип содержимого
ответа ``
Объект HttpServletResponse
имеет метод setContentType
, который мы можем использовать для установки заголовка Content-Type
ответа HTTP.
Content-Type
— это историческое имя свойства заголовка. Другим названием был тип MIME (многоцелевые расширения почты Интернета). Теперь мы просто ссылаемся на значение как тип носителя.
Это значение может быть «application/pdf», «text/plain», «text/html», «image/jpg» и т . д . Официальный список поддерживается Управлением по присвоению номеров в Интернете (IANA), и его можно найти здесь . .
В нашем примере мы используем простой текстовый файл. Content - Type
для текстового файла — «text/plain».
3.3. Ответ Content-Disposition
Установка заголовка Content-Disposition
в объекте ответа сообщает браузеру, как обрабатывать файл, к которому он обращается.
Браузеры понимают использование Content-Disposition
как соглашение, но на самом деле это не часть стандарта HTTP. У W3 есть памятка по использованию Content-Disposition
, которую можно прочитать здесь .
Значения Content-Disposition
для основной части ответа будут либо «встроенными» (для отображения содержимого веб-страницы), либо «вложениями» (для загружаемого файла).
Если не указано иное, Content-Disposition
по умолчанию является «встроенным».
Используя необязательный параметр заголовка, мы можем указать имя файла «sample.txt».
Некоторые браузеры немедленно загрузят файл, используя заданное имя файла, а другие отобразят диалоговое окно загрузки, содержащее наше предопределенное значение.
Точное предпринятое действие будет зависеть от браузера.
3.4. Чтение из файла и запись в выходной поток
В оставшихся строках кода мы берем ServletContext
из запроса и используем его для получения файла в «/WEB-INF/sample.txt».
Используя HttpServletResponse
# getOutputStream()
, мы затем читаем из входного потока ресурса и записываем в OutputStream
ответа .
Размер используемого нами массива байтов произволен. Мы можем определить размер на основе объема памяти, который разумно выделить для передачи данных из InputStream
в OutputStream
; чем меньше число, тем больше петель; чем больше число, тем выше использование памяти.
Этот цикл продолжается до тех пор, пока numByteRead
не станет равным 0, поскольку это указывает на конец файла.
3.5. Закрыть и сбросить
Экземпляры потока
должны быть закрыты после использования, чтобы высвободить все ресурсы, которые он в настоящее время удерживает. Экземпляры
модуля записи также должны быть сброшены, чтобы записать любые оставшиеся буферизованные байты в место назначения.
Используя оператор try-with-resources
, приложение автоматически закроет
любой экземпляр AutoCloseable
, определенный как часть оператора try
. Подробнее о try-with-resources читайте здесь .
Мы используем эти два метода для освобождения памяти, гарантируя, что подготовленные нами данные будут отправлены из нашего приложения.
3.6. Загрузка файла
Теперь, когда все готово, мы готовы запустить наш сервлет.
Теперь, когда мы посещаем относительную конечную точку «/download»
, наш браузер попытается загрузить файл как «simple.txt».
4. Вывод
Загрузка файла из сервлета становится простым процессом. Использование потоков позволяет нам передавать данные в виде байтов, а типы мультимедиа сообщают браузеру клиента, какой тип данных ожидать.
Браузер должен определить, как обрабатывать ответ, однако мы можем дать некоторые рекомендации с заголовком Content-Disposition .
Весь код в этой статье можно найти на GitHub .