ファイルアップロードの実装概要
JavaWebアプリケーションにおいて、ファイルのアップロードは非常に一般的な機能です。標準のServlet APIのみで実装することも可能ですが、柔軟性と利便性の観点から、Apacheが提供するオープンソースライブラリである「Apache Commons FileUpload」を使用するのが一般的です。
1. 開発環境の準備
本機能を実装するには、以下の2つのライブラリが必要です。Mavenなどのビルドツールを使用するか、jarファイルをプロジェクトのWEB-INF/libに配置してください。
- commons-fileupload: ファイルアップロードのコアロジック。
- commons-io: 入出力処理を補助する依存ライブラリ。
2. セキュリティと実装のポイント
安全で堅牢なアップロード機能を構築するために、以下の点に注意する必要があります。
- 保存場所の保護: アップロードされたファイルは、ブラウザから直接アクセスできない
WEB-INF配下などに保存することを推奨します。 - ファイル名の重複防止: ユーザーがアップロードしたファイル名が重複すると上書きされるリスクがあるため、UUIDなどを用いて一意のファイル名を生成します。
- 容量制限: サーバーリソースの枯渇を防ぐため、1ファイルあたりのサイズおよびリクエスト全体の合計サイズに上限を設けます。
- フォームの属性: HTMLの
<form>タグには、必ずmethod="post"とenctype="multipart/form-data"を指定する必要があります。
3. フロントエンドの実装 (JSP/HTML)
ファイルを選択するための入力フォームを作成します。テキストデータとファイルデータを混在させて送信可能です。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ファイルアップロード画面</title>
</head>
<body>
<h2>ファイルのアップロード</h2>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
ユーザー名: <input type="text" name="userName"><br>
添付ファイル1: <input type="file" name="attachment1"><br>
添付ファイル2: <input type="file" name="attachment2"><br>
<input type="submit" value="送信">
</form>
</body>
</html>
4. バックエンドの実装 (Servlet)
ServletFileUploadクラスを使用してリクエストを解析し、ファイルをサーバーに保存するロジックを記述します。
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
public class FileUploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// マルチパートリクエストか確認
if (!ServletFileUpload.isMultipartContent(request)) {
return;
}
// 保存先パスの設定
String storageBasePath = getServletContext().getRealPath("/WEB-INF/uploads");
File storageDir = new File(storageBasePath);
if (!storageDir.exists()) storageDir.mkdirs();
// 一時保存用パス
String tempPath = getServletContext().getRealPath("/WEB-INF/temp");
File tempDir = new File(tempPath);
if (!tempDir.exists()) tempDir.mkdirs();
try {
// 1. ファクトリの設定
DiskFileItemFactory diskFactory = new DiskFileItemFactory();
diskFactory.setSizeThreshold(1024 * 1024); // 1MBを超えたら一時ディレクトリを使用
diskFactory.setRepository(tempDir);
// 2. アップローダーの初期化
ServletFileUpload fileUploader = new ServletFileUpload(diskFactory);
fileUploader.setHeaderEncoding("UTF-8");
fileUploader.setFileSizeMax(1024 * 1024 * 5); // 単一ファイル5MB制限
// 3. リクエストの解析
List<FileItem> items = fileUploader.parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// 通常のフォームフィールド
String fieldName = item.getFieldName();
String fieldValue = item.getString("UTF-8");
System.out.println(fieldName + " : " + fieldValue);
} else {
// ファイルデータ
String originalName = item.getName();
if (originalName == null || originalName.trim().isEmpty()) continue;
// ファイル名のみを抽出
String fileName = originalName.substring(originalName.lastIndexOf(File.separator) + 1);
// 一意なディレクトリ作成
String uniqueFolder = UUID.randomUUID().toString();
String finalSavePath = storageBasePath + File.separator + uniqueFolder;
new File(finalSavePath).mkdirs();
// ストリーム処理
try (InputStream in = item.getInputStream();
FileOutputStream out = new FileOutputStream(finalSavePath + File.separator + fileName)) {
byte[] buffer = new byte[2048];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
}
item.delete(); // 一時ファイルの削除
}
}
request.setAttribute("result", "アップロードが完了しました。");
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("result", "エラーが発生しました: " + e.getMessage());
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
5. Webアプリケーションの設定 (web.xml)
サーブレットをマッピングして、URLからアクセスできるように設定します。
<servlet>
<servlet-name>FileUploadServlet</servlet-name>
<servlet-class>com.example.servlet.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>