Servlet 3 ファイルのアップロード – @MultipartConfig、Part

今日は、@MultipartConfigアノテーションとjavax.servlet.http.Partを使用したServlet 3のファイルアップロードの例を見ていきます。以前、Servletファイルアップロードに関する記事を書いたことがありますが、そこではApache FileUpload APIを使用しましたが、ここではServlet 3のファイルアップロード機能を使用します。

サーブレット3のファイルアップロード

ウェブアプリケーションにおいて、ファイルのアップロードは一般的なタスクですので、Servlet Specs 3.0では追加のサポートが提供され、サーバーへのファイルのアップロードについては第三者のAPIに依存する必要がありません。このチュートリアルでは、Servlet 3.0 APIを使用してファイルをサーバーにアップロードする方法を見ていきます。

マルチパート構成

私たちは、ファイルをサーバーにアップロードするために使用されるmultipart/form-dataリクエストを処理するために、File UploadハンドラーサーブレットにMultipartConfigアノテーションを付ける必要があります。MultipartConfigアノテーションには、以下の属性があります。

  • fileSizeThreshold: We can specify the size threshold after which the file will be written to disk. The size value is in bytes, so 1024*1024*10 is 10 MB.
  • location: Directory where files will be stored by default, it’s default value is “”.
  • maxFileSize: Maximum size allowed to upload a file, it’s value is provided in bytes. It’s default value is -1L means unlimited.
  • maxRequestSize: Maximum size allowed for multipart/form-data request. Default value is -1L that means unlimited.

「Javaのアノテーションチュートリアルでアノテーションについてさらに詳しく読む」

パートインターフェース

「Part インターフェースは、multipart/form-data POST リクエスト内で受信したパートまたはフォームアイテムを表します。getInputStream() メソッド、write(String fileName) メソッドなど、ファイルの読み書きに使用できる重要なメソッドがあります。」

HttpServletRequestの変更

HttpServletRequestには新しいメソッドが追加され、getParts()メソッドを通じてmultipart/form-dataリクエストのすべてのパーツを取得することができます。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.scdev.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 {
        // gets absolute path of the web application
        String applicationPath = request.getServletContext().getRealPath("");
        // constructs path of the directory to save uploaded file
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
         
        // creates the save directory if it does not exists
        File fileSaveDir = new File(uploadFilePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdirs();
        }
        System.out.println("Upload File Directory="+fileSaveDir.getAbsolutePath());
        
        String fileName = null;
        //Get all the parts from request and write it to the file on server
        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 "";
    }
}

クライアントから送信されるファイル名を取得するために、リクエストヘッダー「content-disposition」属性を使用する必要があります。ファイル名は同じ名前で保存されます。ファイルの保存場所は、ファイルを保存しているWebアプリケーションに対して相対的なディレクトリです。Apache Commons FileUploadの例のように、別の場所に設定することもできます。 @MultipartConfig注釈の使用に注意してください。

JSPへの応答

ファイルがサーバーに正常にアップロードされた場合、クライアントにレスポンスとして送信されるシンプルなJSPページです。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>

ディプロイメント記述子

servletファイルのアップロードに関しては、web.xmlファイルには何も新しい情報はありません。それは単にindex.htmlをウェルカムファイルとして使用するためのものです。

<?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/scdev/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"

Eclipseを通じてTomcatを起動しているため、ファイルの場所がこのようになっています。もしコマンドラインからTomcatを起動し、アプリケーションをWARファイルとしてエクスポートして、webappsディレクトリに展開する場合、異なる構造になりますが、より明確なものとなります。

「Servlet 3のマルチパートファイルアップロードプロジェクトをダウンロードする」

コメントを残す 0

Your email address will not be published. Required fields are marked *