はじめに (対象読者・この記事でわかること)
この記事は、JavaEE(Servlet 3.x/JSP 2.x)で「画像アップロード+一覧表示」を実装中に「画像が表示されない」「リストが空」などの壁に突き当たった開発者を対象としています。
記事を読み終えると、以下のことがわかります。
- アップロードした画像が「サーバー上にちゃんと保存されているか」の確認手順
- JSP側で
<img src="...">と書いても画像が表示されない根本原因と、正しいコンテキストパスの扱い方 Partインターフェースでファイル名を取得する際の「Chrome vs 他ブラウザ」差分を吸収するコード- 画像リストを「再起動後も残す」「再起動後はクリア」の2パターンで実装する際の注意点
この記事を書いたのは、社内のレガシー環境(JavaEE 7、WildFly 26)で「ドラッグ&ドロップで画像アップロード」機能を追加した際、画像表示まで丸1日つまずんだ経験があるからです。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- JavaEE の基本的なディレクトリ構成(
WEB-INF、コンテキストルートの概念) - Servlet 3.x で提供される
@MultipartConfigアノテーション - JSP での JSTL(
<c:forEach>)と EL(${})の記法
JavaEE でのファイルアップロードの仕組みと「見えない」理由
JavaEE 標準だけでファイルアップロードを実装する場合、HttpServletRequest#getPart を使います。
@MultipartConfig をクラスに付与すると、サーバーがマルチパートリクエストを自動でパースしてくれます。
Java@WebServlet("/upload") @MultipartConfig(location = "/tmp", maxFileSize = 5 * 1024 * 1024) public class UploadServlet extends HttpServlet { ... }
ここで「画像が表示されない」根本原因の90%は、以下の2つに集約されます。
- アップロード先ディレクトリが「ウェブコンテンツとして公開されていない」
- JSP側で誤ったパスを
<img src>に指定している
JavaEE のルール上、WEB-INF以下のファイルは直接ブラウザからアクセスできません。
そのため、/WEB-INF/uploaded/以下に画像を置いたままでは、ブラウザが画像をリクエストしても404が返ります。
画像アップロード&一覧表示を0から実装してみる
ステップ1:公開可能なディレクトリを用意する
アプリケーションのルート(WebContentやsrc/main/webapp)にuploadsフォルダを作ります。
これはhttp://localhost:8080/<context-root>/uploads/...で直接アクセス可能な位置です。
Bashsrc/main/webapp ├─ uploads ← ここに画像を保存 ├─ WEB-INF └─ index.jsp
アップロード先の絶対パスを取得するには、ServletContext#getRealPathを使います。
JavaString uploadDir = getServletContext().getRealPath("/uploads"); File repo = new File(uploadDir); if (!repo.exists()) repo.mkdirs();
ステップ2:Part → ファイル保存までの一連処理
ブラウザ差分を吸収するため、ファイル名抽出メソッドを切り出しておきます。
Javaprivate String getFileName(Part part) { String cd = part.getHeader("Content-Disposition"); if (cd == null) return null; for (String seg : cd.split(";")) { if (seg.trim().startsWith("filename")) { return seg.substring(seg.indexOf('=') + 1) .replace("\"", ""); } } return null; }
アップロード処理本体:
JavaPart filePart = request.getPart("file"); String fileName = getFileName(filePart); if (fileName == null || fileName.isEmpty()) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "ファイル名が取得できません"); return; } String ext = fileName.substring(fileName.lastIndexOf('.')); String savedName = UUID.randomUUID() + ext; File saveFile = new File(uploadDir, savedName); filePart.write(saveFile.getAbsolutePath()); // 一覧表示用にセッションに保存(単純な例) @SuppressWarnings("unchecked") List<String> list = (List<String>) request.getSession() .getAttribute("images"); if (list == null) { list = new ArrayList<>(); request.getSession().setAttribute("images", list); } list.add("uploads/" + savedName); response.sendRedirect("list.jsp");
ステップ3:JSP側で一覧表示
list.jspでは、保存したパスをそのまま<img>に埋め込みます。
Jsp<c:forEach var="path" items="${sessionScope.images}"> <div> <img src="${pageContext.request.contextPath}/${path}" width="200"> <p>${path}</p> </div> </c:forEach>
ポイントは${pageContext.request.contextPath}を先頭に付けること。
これを忘れると、コンテキストルートが省略され「404 Not Found」が返されます。
ハマった点・エラー解決
現象A:「Partがnull」と例外が出る
formタグにenctype="multipart/form-data"が指定されていないと、request.getPartはnullを返します。
必ず以下を確認しましょう。
Html<form action="upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <button>アップロード</button> </form>
現象B:「ファイル名が日本語だと文字化けする」
WildFly/Tomcatともに、URIEncoding設定が必要です。
Tomcatの例(conf/server.xml):
Xml<Connector port="8080" URIEncoding="UTF-8" />
現象C:「再起動したら画像リストが消える」
サンプルではセッションにパスを保持しているため、アプリケーション再起動でリストが空になります。
永続化が必要な場合は、DBや外部ファイル(JSON/CSV)に保存するか、ServletContextListenerでList<String>をServletContextに保持する方法もあります。
解決策まとめ
- 画像保存先は
WEB-INF外に置く <img src>には常に${pageContext.request.contextPath}を付与- ファイル名抽出は
Content-Dispositionを自分でパースする - 日本語ファイル名はサーバー側のエンコーディング設定を確認
まとめ
本記事では、JavaEE(Servlet/JSP)だけで「画像アップロード&一覧表示」を実装する際の落とし穴と、正しいディレクトリ配置・パス指定方法を解説しました。
- アップロード先は
getServletContext().getRealPath("/uploads")で取得し、公開ディレクトリに保存 - JSP側で画像を表示する際は
${pageContext.request.contextPath}を絶対に付ける - Partからのファイル名取得はブラウザ差分を吸収したヘルパーメソッドを用意
- 永続化が必要ならセッションではなくファイルorDBに保存
この記事を通して、レガシーながらもJavaEE標準だけで手軽に画像アップロード機能を追加できることが伝われば幸いです。
次回は「ドラッグ&ドロップ対応+Progress Bar実装」について、Vue.jsとAjaxを使った手法を紹介する予定です。
参考資料
- JavaEE 7 Tutorial – File Upload
- Apache Tomcat – Multipart Configuration
- Jakarta Servlet 5.0 API – Part Interface
