👻

【Servlet・JSP】画像ファイルアップロードについて

に公開

Tomcatが使用している場所にアップ

ファイルを指定してアップロードする画面


webapp\upload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<html>
<head>
<title>画像ファイルアップロード</title>
</head>
<body>
	<form action="upload" method="post" enctype="multipart/form-data">
		画像を選択:<br> <input type="file" name="image"><br>
		<br> <input type="submit" value="アップロード">
	</form>
</body>
</html>

アップした結果と画像を表示する画面

<%@ page contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>アップロード結果</title>
</head>
<body>
	<p>画像をアップロードしました!</p>
	<p>ファイル名:${fileName}</p>

	<p>画像プレビュー:</p>
	<img src="uploads/${fileName}" alt="アップロード画像" width="300">
	<br>
	<a href="upload.jsp">戻る</a>
</body>
</html>

ファイルアップロード処理を行うサーブレット

package servlet;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

@WebServlet("/upload")
//ファイルアップロードを受け付けますよという宣言
@MultipartConfig
public class UploadServlet extends HttpServlet {

	// アップロードされたファイルを保存するフォルダ
	//プロジェクト内にフォルダは作成しないでOK
	//サーバーが動くときに、自動的に生成(Tomcatが仮展開する場所に)
	private static final String UPLOAD_DIR = "uploads";

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 保存ディレクトリのパス(アプリケーションのルートから相対パス)
		//フォルダの場所を取得
		String appPath = request.getServletContext().getRealPath("");
		//↑のuploadsフォルダの場所
		String savePath = appPath + File.separator + UPLOAD_DIR;

		// フォルダがなければ作成
		File uploadDir = new File(savePath);
		if (!uploadDir.exists())
			uploadDir.mkdir();

		// ブラウザから送られてきたファイル(`name="image"`)を受け取る
		//getSubmittedFileName():アップロードされたファイルの「元の名前」を取得
		Part part = request.getPart("image");
		String fileName = Paths.get(part.getSubmittedFileName()).getFileName().toString();

		// ファイル保存
		part.write(savePath + File.separator + fileName);

		//実際に保存されている場所
		//サーバを再公開した場合はファイルはなくなる可能性あり
		System.out.println(request.getServletContext().getRealPath(""));

		// JSPにファイル名を渡す
		request.setAttribute("fileName", fileName);
		request.getRequestDispatcher("/result.jsp").forward(request, response);
	}
}


C:\imagesに画像をアップする場合

upload2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<html>
<head>
<title>画像ファイルアップロード</title>
</head>
<body>
	<form action="upload2" method="post" enctype="multipart/form-data">
		画像を選択:<br> <input type="file" name="image"><br>
		<br> <input type="submit" value="アップロード">
	</form>
</body>
</html>

result2.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>アップロード結果</title>
</head>
<body>
	<p>画像をアップロードしました!</p>
	<p>ファイル名:${fileName}</p>

	<p>画像プレビュー:</p>
	<img src="${pageContext.request.contextPath}/images/${fileName}" alt="アップ画像" width="300">
	<br>
	<a href="upload.jsp">戻る</a>
</body>
</html>
package servlet;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

@WebServlet("/upload2")
//ファイルアップロードを受け付けますよという宣言
@MultipartConfig
public class UploadServlet2 extends HttpServlet {

	// アップロードされたファイルを保存するフォルダ
	private static final String SAVE_DIR = "C:/images";

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
	        throws ServletException, IOException {

		//フォルダの場所を表すオブジェクトを作成
	    File uploadDir = new File(SAVE_DIR);
	    //.exists() で「そのフォルダがすでにあるか?」をチェック
	    //.mkdirs() は、なければフォルダを自動で作る命令
	    if (!uploadDir.exists()) uploadDir.mkdirs();

	    //アップロードされたファイルを受け取る
	    Part part = request.getPart("image");
	    //アップロードされたファイルの「名前」を取得
	    String fileName = Paths.get(part.getSubmittedFileName()).getFileName().toString();

	    // ファイルを保存
	    //SAVE_DIR + File.separator + fileNameでC:/images/dog.jpgを作っている
	    part.write(SAVE_DIR + File.separator + fileName);

	    request.setAttribute("fileName", fileName);
	    request.getRequestDispatcher("/result2.jsp").forward(request, response);
	}
}

C:/images/sample.jpg のようなファイルを、
Webサーバー経由で「/images/sample.jpg」として見せかけるために必要

package servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

// /images/ファイル名 というURLで呼び出される
//例:http://localhost:8080/yourapp/images/sample.jpg→ sample.jpg を探してブラウザに表示
@WebServlet("/images/*")
public class ImageServlet extends HttpServlet {

	// 保存してある画像のディレクトリ(ローカルパス)
	private static final String IMAGE_DIR = "C:/images";

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// /images/sample.jpg にアクセスした場合、ここで /sample.jpgを取得
		String requestedFile = request.getPathInfo(); // /xxx.jpg
		
		//ファイルがない or 読めないときは「404エラー(見つからない)」を返
		if (requestedFile == null || requestedFile.equals("/")) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404
			return;
		}

		File imageFile = new File(IMAGE_DIR, requestedFile);

		// ファイルが存在しない or 読めない場合
		if (!imageFile.exists() || !imageFile.canRead()) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404
			return;
		}

		// MIMEタイプ設定(画像拡張子から自動判定)
		String mimeType = getServletContext().getMimeType(imageFile.getName());
		if (mimeType == null) {
			mimeType = "application/octet-stream";
		}
		response.setContentType(mimeType);
		response.setContentLength((int) imageFile.length());

		// 画像を読み込んでレスポンスに書き出す
		try (FileInputStream in = new FileInputStream(imageFile);
				OutputStream out = response.getOutputStream()) {

			//byte[]:読み込んだデータを一時的に入れる箱
			//1度に読み込むバイト数(4096は4KB)
			byte[] buffer = new byte[4096];
			
			int bytesRead;
			while ((bytesRead = in.read(buffer)) != -1) {
				//buffer:書き出したいデータが入っている配列(byte[])
				//0:書き出しの開始位置(オフセット)。ここでは buffer[0] からスタート
				//bytesRead	書き出す長さ(バイト数)
				out.write(buffer, 0, bytesRead);
			}
		}
	}
}

Discussion