Загрузка файлов Servlet 3 – @MultipartConfig, Часть

Сегодня мы рассмотрим пример загрузки файлов с помощью использования аннотации @MultipartConfig и класса javax.servlet.http.Part в сервлете 3. Некоторое время назад я написал статью о загрузке файлов в сервлет и использовал API Apache FileUpload, но здесь мы будем использовать возможности загрузки файлов в сервлете 3.

Загрузка файлов в сервлете 3

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

Аннотация MultipartConfig

Нам необходимо пометить обработчик загрузки файлов сервлета аннотацией MultipartConfig для обработки запросов типа multipart/form-data, которые используются для загрузки файлов на сервер. Аннотация MultipartConfig имеет следующие атрибуты:

  • fileSizeThreshold: Мы можем указать пороговое значение размера, после которого файл будет записан на диск. Значение размера указывается в байтах, поэтому 1024*1024*10 соответствует 10 МБ.
  • Местоположение: Каталог, в котором файлы будут храниться по умолчанию. Его значение по умолчанию – “”.
  • maxFileSize: Максимальный размер разрешенного для загрузки файла, его значение указывается в байтах. Значение по умолчанию – -1L, что означает неограниченный размер.
  • maxRequestSize: Максимальный размер, разрешенный для запроса multipart/form-data. Значение по умолчанию – -1L, что означает неограниченный размер.

Более подробно об аннотациях можно прочитать в Руководстве по аннотациям в Java.

Интерфейс Part

Интерфейс Part представляет собой часть или элемент формы, полученные в запросе POST в формате multipart/form-data. Некоторые важные методы – getInputStream(), write(String fileName), которые можно использовать для чтения и записи файла.

Изменения в HttpServletRequest

В класс HttpServletRequest добавлены новые методы для получения всех частей в запросе multipart/form-data с помощью метода getParts(). Мы можем получить определенную часть с помощью метода getPart(String partName). Давайте рассмотрим простой проект, в котором мы будем использовать вышеуказанные методы API для загрузки файла с помощью сервлета. Структура нашего проекта будет выглядеть как на изображении ниже.

HTML-форма

У нас есть простая HTML-страница, на которой мы можем выбрать файл для загрузки и отправить запрос на сервер для его загрузки. index.html

<html>
<head></head>
<body>
<form action="FileUploadServlet" method="post" enctype="multipart/form-data">
Select File to Upload:<input type="file" name="fileName">
<br>
<input type="submit" value="Upload">
</form>
</body>
</html>

Сервлет загрузки файла

Вот реализация нашего сервлета загрузки файла. FileUploadServlet.java

package com.journaldev.servlet;
 
import java.io.File;
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
 
@WebServlet("/FileUploadServlet")
@MultipartConfig(fileSizeThreshold=1024*1024*10, 	// 10 MB 
                 maxFileSize=1024*1024*50,      	// 50 MB
                 maxRequestSize=1024*1024*100)   	// 100 MB
public class FileUploadServlet extends HttpServlet {
 
    private static final long serialVersionUID = 205242440643911308L;
	
    /**
     * Directory where uploaded files will be saved, its relative to
     * the web application directory.
     */
    private static final String UPLOAD_DIR = "uploads";
     
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // получаем абсолютный путь веб-приложения
        String applicationPath = request.getServletContext().getRealPath("");
        // формируем путь к каталогу для сохранения загруженного файла
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
         
        // создаем каталог сохранения, если его не существует
        File fileSaveDir = new File(uploadFilePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdirs();
        }
        System.out.println("Upload File Directory="+fileSaveDir.getAbsolutePath());
        
        String fileName = null;
        // Получаем все части из запроса и записываем их в файл на сервере
        for (Part part : request.getParts()) {
            fileName = getFileName(part);
            part.write(uploadFilePath + File.separator + fileName);
        }
 
        request.setAttribute("message", fileName + " File uploaded successfully!");
        getServletContext().getRequestDispatcher("/response.jsp").forward(
                request, response);
    }
 
    /**
     * Utility method to get file name from HTTP header content-disposition
     */
    private String getFileName(Part part) {
        String contentDisp = part.getHeader("content-disposition");
        System.out.println("content-disposition header= "+contentDisp);
        String[] tokens = contentDisp.split(";");
        for (String token : tokens) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length()-1);
            }
        }
        return "";
    }
}

Обратите внимание на использование аннотации @MultipartConfig для указания параметров размера файла для загрузки. Нам нужно использовать атрибут заголовка запроса “content-disposition”, чтобы получить имя файла, отправленное клиентом, мы сохраним файл с тем же именем. Расположение каталога относительно веб-приложения, где мы сохраняем файл, можно настроить на другое место, например, в примере Apache Commons FileUpload.

Ответ JSP

A simple JSP page that will be sent as response to client once the file is uploaded successfully to server. response.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Upload File Response</title>
</head>
<body>
	<%-- Using JSP EL to get message attribute value from request scope --%>
    <h2>${requestScope.message}</h2>
</body>
</html>

Дескриптор развертывания

В файле web.xml для загрузки сервлета нет ничего нового, он используется только для установки index.html в качестве файла приветствия. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>ServletFileUploadExample</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

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

Upload File Directory=/Users/pankaj/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ServletFileUploadExample/uploads
content-disposition header= form-data; name="fileName"; filename="IMG_2046.jpg"

I am running Tomcat through Eclipse, that’s why file location is like this. If you run tomcat through command line and deploy application by exporting as WAR file into webapps directory, you will get different structure but a clear one.

Скачать проект загрузки многопользовательского файла сервлета 3

Source:
https://www.digitalocean.com/community/tutorials/servlet-3-file-upload-multipartconfig-part