JSP と Servlet 使ってファイルアップロードをやってみる
アップロードでやるざっくり内容
- フォルダ
- アップロード用のフォルダ作成
/java-webapp-clump/src/main/webapp/upload
- tomcat で読み込まれるように blankファイルを配置
- アップロード用のフォルダ作成
- JSP
- 入力送信用のformタグに
enctype="multipart/form-data"
を追加 - 入力送信用のformタグの中にある input タグに
type="file"
を追加 - アップロード表示用のタグを配置 (ここでは 画像 img, 動画(・音声) video のサンプルでやってみます )
- 入力送信用のformタグに
- Servlet
- クラスのアノテーションに
@MultipartConfig
を追加 -
request.getPart("JSPで設定したname")
で入力したファイルを取得 -
getServletContext()
でサーバに展開してるフォルダパスを取得し/upload/アップロードファイル名
で保存 - JSP に保存したファイルパス (
/upload/アップロードファイル名
) を返す
- クラスのアノテーションに
※アップロード直後に表示すると保存・転送が間に合わずにアップロードファイルが開けない...
※リロードすればそのうち取得できます
※サンプルではJavaScriptの処理いれて簡易なローディングっぽいの差し込んでみてます...
JSP, Servlet 使ってファイルアップロード(ファイル保存して表示)
ここで使ってるサンプルのおおもとはこちら JSP と Servlet ざっくりまとめ を参考にお願いします
1. アップロードファイルを保存するフォルダを作成
2. JSP : 入力送信用のタグ(form タグ) にファイルアップロード設定, アップロード表示用のタグを配置
-
/java-webapp-clump/src/main/webapp/WEB-INF/view/uploadFile.jsp
を作成 - form タグの
action="upload_file"
,method="post"
,enctype="multipart/form-data"
を設定 - form タグの中の input タグに
type="file"
を追加, 必須チェックとしてrequired
を設定
uploadFile.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page isELIgnored="false" %>
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>JavaDevelop</title>
<link rel="shortcut icon" href="<c:url value="/assets/favicon.ico" />">
<link rel="stylesheet" href="<c:url value="/assets/bootstrap.min.css" />">
<link rel="stylesheet" href="<c:url value="/assets/bootstrap-icons.css" />">
<link rel="stylesheet" href="<c:url value="/assets/styles.css" />">
</head>
<body>
<%@ include file="./_headerNavbar.jsp" %>
<main>
<div class="container workspace">
<form action="upload_file" method="post" enctype="multipart/form-data">
<label>ファイル 画像:</label>
<input type="file" name="img" />
<br/>
<label>ファイル 音声:</label>
<input type="file" name="audio" />
<br/>
<label>ファイル 動画:</label>
<input type="file" name="video" />
<br/>
<input type="submit" />
</form>
<hr/>
<div class="upload">
<p>アップロードファイル:画像</p>
<c:if test="${!empty resultDto.imgPath}">
<div class="spinner-border d-none uploadFileLoading"></div>
<img class="uploadFile" src="<c:url value="${resultDto.imgPath}" />" />
</c:if>
</div>
<hr/>
<div class="upload">
<p>アップロードファイル:音声</p>
<c:if test="${!empty resultDto.audioPath}">
<div class="spinner-border d-none uploadFileLoading"></div>
<audio class="uploadFile" src="<c:url value="${resultDto.audioPath}" />" controls></audio>
</c:if>
</div>
<hr/>
<div class="upload">
<p>アップロードファイル:動画</p>
<c:if test="${!empty resultDto.videoPath}">
<div class="spinner-border d-none uploadFileLoading"></div>
<video class="uploadFile" src="<c:url value="${resultDto.videoPath}" />" controls></video>
</c:if>
</div>
<hr/>
</div>
</main>
<footer class="footer mt-auto fixed-bottom py-3 bg-secondary"></footer>
<script src="<c:url value="/assets/bootstrap.bundle.min.js" />"></script>
<script src="<c:url value="/assets/script.js" />"></script>
</body>
</html>
3. Servlet : ファイル保存してJSPに保存したファイルを返す
-
/java-webapp-clump/src/main/java/presentation/servlet/UploadFileServlet.java
を作成 - クラスのアノテーションに
@WebServlet("/uplaod_file")
,@MultipartConfig
を設定 -
Part part = request.getPart("JSPで設定した name ");
で入力したファイルを取得 -
String filePath = "/upload/" + part.getSubmittedFileName();
でJSPで使うファイルパスを作成 -
part.write(getServletContext().getRealPath(filePath));
でアップロードしたファイルをサーバに保存 -
request.setAttribute("resultDto", new Dto(filePath));
でファイルパスを DTO に設定して JSP に返す
※ DTO(UploadFile.java) を作成, インスタンス変数imgPath, audioPath, videoPath
を追加してコンストラクタ、getter(, setter) を追加しておく
UplaodFileServlet.java
package presentation.servlet;
import java.io.IOException;
import java.util.function.Consumer;
import javax.servlet.RequestDispatcher;
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;
import dto.UploadFile;
/**
* {@link UploadFileServlet}
*/
@WebServlet("/upload_file")
@MultipartConfig
public class UploadFileServlet extends HttpServlet {
/**
* {@inheritDoc}
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String view = "/WEB-INF/view/uploadFile.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(view);
dispatcher.forward(request, response);
}
/**
* {@inheritDoc}
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
UploadFile dto = new UploadFile();
fileUpload(request.getPart("img"), (s) -> dto.setImgPath(s));
fileUpload(request.getPart("audio"), (s) -> dto.setAudioPath(s));
fileUpload(request.getPart("video"), (s) -> dto.setVideoPath(s));
request.setAttribute("resultDto", dto);
doGet(request, response);
}
/**
* ファイルアップロードしてファイルパスを設定します
*
* @param part パート
* @param function ファイルパス設定処理
* @throws IOException ファイル書込時の例外
*/
private void fileUpload(Part part, Consumer<String> function) throws IOException {
if ("".equals(part.getSubmittedFileName())) {
return;
}
String filePath = "/upload/" + part.getSubmittedFileName();
part.write(getServletContext().getRealPath(filePath));
function.accept(filePath);
}
}
UploadFile.java
package dto;
/**
* {@link UploadFile}
*/
public class UploadFile {
/** 画像パス */
private String imgPath;
/** 音声パス */
private String audioPath;
/** 動画パス */
private String videoPath;
/**
* コンストラクタ
*/
public UploadFile() {
}
/**
* コンストラクタ
* @param imgPath 画像パス
* @param audioPath 音声パス
* @param videoPath 動画パス
*/
public UploadFile(String imgPath, String audioPath, String videoPath) {
this.imgPath = imgPath;
this.audioPath = audioPath;
this.videoPath = videoPath;
}
/**
* @return imgPath
*/
public String getImgPath() {
return imgPath;
}
/**
* @param imgPath セットする imgPath
*/
public void setImgPath(String imgPath) {
this.imgPath = imgPath;
}
/**
* @return audioPath
*/
public String getAudioPath() {
return audioPath;
}
/**
* @param audioPath セットする audioPath
*/
public void setAudioPath(String audioPath) {
this.audioPath = audioPath;
}
/**
* @return videoPath
*/
public String getVideoPath() {
return videoPath;
}
/**
* @param videoPath セットする videoPath
*/
public void setVideoPath(String videoPath) {
this.videoPath = videoPath;
}
}
4. ここまでやったら動作確認
- http://localhost:8080/java-wabapp-clump/upload_file をブラウザで表示
- ファイルを選択して送信を実行
- ブラウザ表示でエラーがないのにアップロードファイル表示されない時は更新すれば表示されるはず
XX. アップロードファイルが表示されるように自動更新を JavaScript でやってみる
uploadFile.jsp
にローディング用のタグはすでに設定済みなので JavaScript のみ対応を追加
XX-1. JavaScript にアップロードファイル更新の処理を追加
-
/java-webapp-clump/src/main/webapp/assets/script.js
を修正・追記 - html 読込時の処理 に function(メソッド)呼び出しを追加
applyUploadFileWait();
- function(メソッド) ファイル更新待ち設定
applyUploadFileWait()
作成 - function(メソッド) ファイル更新
updateSrc(dom)
作成 - function(メソッド) ファイル表示
loadSrc(dom, domLoading)
作成
script.js
・
・
/**
* html 読込時の処理
*/
window.addEventListener('load', (e) => {
pageLinks.forEach((links, i) => {
applyNavbar(links);
applyCarousel(links, i);
});
// 追加するのは下の行のfunction(メソッド)呼び出し
applyUploadFileWait();
});
・
・
// function(メソッド)を追加
/**
* アップロードファイル更新待ち設定
*/
function applyUploadFileWait() {
document.querySelectorAll('.upload').forEach(uploadDom => {
let dom = uploadDom.querySelector('.uploadFile');
if (!dom || !['IMG', 'VIDEO', 'AUDIO'].includes(dom.tagName)) return;
let domLoding = uploadDom.querySelector('.uploadFileLoading');
dom.onerror = () => updateSrc(dom);
if (dom.tagName == 'IMG') {
dom.onload = () => loadSrc(dom, domLoding);
} else {
dom.onloadedmetadata = () => loadSrc(dom, domLoding);
}
dom.classList.add('d-none');
domLoding.classList.remove('d-none');
updateSrc(dom);
});
}
/**
* ファイル更新
*
* @param dom
* メディアDOM(img, video など)
*/
function updateSrc(dom) {
let src = dom.src;
dom.src = '';
dom.src = src;
}
/**
* ファイル表示
*
* @param dom
* メディアDOM(img, video など)
* @param domLoding
* ローディングDOM
*/
function loadSrc(dom, domLoding) {
domLoding.classList.add('d-none');
dom.classList.remove("d-none");
}
XX-2. ここまでやったら動作確認
- http://localhost:8080/java-wabapp-clump/upload_file をブラウザで表示
- ファイルを選択して送信を実行
- ローディングが表示されてアップロードファイルがそのうち表示されるはず
ここから先はご自由に!
画像、動画、音声を分けて登録できるようにするとかでそれっぽくなりそう
いれたやつの一覧表示とか...
JSP, Servlet 使ってファイルアップロード(サンプル WorkServlet.java, work.jsp に追加)
ここで使ってるサンプルのおおもとはこちら JSP と Servlet ざっくりまとめ を参考にお願いします
WorkServlet.java, work.jsp に追加する形で進めてます
1. アップロードファイルを保存するフォルダを作成
2. JSP : 入力送信用のタグ(form タグ) にファイルアップロードの設定を追加
-
/java-webapp-clump/src/main/webapp/WEB-INF/view/work.jsp
を修正(mainタブのdivタブ(container workspace)の中) - form タグに
enctype="multipart/form-data"
を追加 - form タグの中の input タグに
type="file"
を追加, 必須チェックとしてrequired
を設定
work.jsp
<!-- 追加するのは下の行の enctype="multipart/form-data" の部分 -->
<form action="web_app_work" method="post" enctype="multipart/form-data">
<label>入力:</label>
<input type="text" name="input1" />
<!-- 追加するのはここから4行 input タブの name はなんでもOK, ここでは次の Servlet と合わせて file1 にしてる -->
<br/>
<label>ファイル:</label>
<input type="file" name="file1" required />
<br/>
<!-- 追加するのはここまで -->
<input type="submit" />
</form>
3. Servlet : ファイル保存してJSPに保存したファイルを返す
-
/java-webapp-clump/src/main/java/presentation/servlet/WorkServlet.java
を修正(doPostメソッドの中) - クラスのアノテーションに
@MultipartConfig
を追加 -
Part part = request.getPart("file");
で入力したファイルを取得 -
String filePath = "/upload/" + part.getSubmittedFileName();
でJSPで使うファイルパスを作成 -
part.write(getServletContext().getRealPath(filePath));
でアップロードしたファイルをサーバに保存 -
request.setAttribute("resultDto", new Work(input1, filePath));
でファイルパスを DTO に設定して JSP に返す
※ DTO にインスタンス変数filePath
を追加してコンストラクタ、getter(, setter) を追加しておく
WorkServlet.java
@WebServlet("/web_app_work")
@MultipartConfig // この行を追加
public class WorkServlet extends HttpServlet {
・
・
・
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String input1 = request.getParameter("input1");
request.setAttribute("result1", "入力したのは " + input1);
// 追加・修正するのはここから6行, コメントアウトしてる sysout は実際の保存するファイルパス確認用
Part part = request.getPart("file1");
String filePath = "/upload/" + part.getSubmittedFileName();
part.write(getServletContext().getRealPath(filePath));
// System.out.println(getServletContext().getRealPath(filePath));
request.setAttribute("resultDto", new Work(input1, filePath));
// 追加・修正するのはここまで
doGet(request, response);
}
・
・
・
}
念のため Work.java の修正・追加箇所をピックアップ
Work.java
/** ファイルパス */
private String filePath;
/**
* コンストラクタ
* @param input 入力値
* @param input ファイルパス
*/
public Work(String input, String filePath) {
this.input = input;
this.filePath = filePath;
}
/**
* filePath を取得します
* @return filePath
*/
public String getFilePath() {
return filePath;
}
/**
* filePath を設定します
* @param filePath ファイルパス
*/
public void setFilePath(String filePath) {
this.filePath = filePath;
}
4. JSP : 表示用のタグを配置(画像 img, 動画(・音声) video)
-
/java-webapp-clump/src/main/webapp/WEB-INF/view/work.jsp
を修正(mainタブのdivタブ(container workspace)の中) - taglibの
c:if
を使ってresultDto.filePath
があるときのみ表示用タグを配置するようにする - 画像アップロードのときは imgタグ、動画(・音声)アップロードのときは videoタグを使う
- img or video タグの src に
<c:url value="${resultDto.filePath}" />
を設定してアップロード保存したファイルを指定
work.jsp
<main>
<div class="container workspace">
・
・
・
<!-- 追加するのは divタグ(container workspace) の最後のところ -->
<hr/>
<p>アップロードファイルを表示してみる</p>
<c:if test="${!empty resultDto.filePath}">
<!-- 画像アップロードのとき ※どっちかのみ残す-->
<img class="uploadFile" src="<c:url value="${resultDto.filePath}" />" />
<!-- 動画(・音声)アップロードのとき ※どっちかのみ残す -->
<video class="uploadFile" src="<c:url value="${resultDto.filePath}" />" controls></video>
</c:if>
</div>
</main>
5. ここまでやったら動作確認
- http://localhost:8080/java-wabapp-clump/web_app_work をブラウザで表示
- ファイルを選択して送信を実行
- ブラウザ表示でエラーがないのにアップロードファイル表示されない時は更新すれば表示されるはず
XX. アップロードファイルが表示されるように自動更新を JavaScript でやってみる
XX-1. JSP にローディングの枠を追加
-
/java-webapp-clump/src/main/webapp/WEB-INF/view/work.jsp
を修正(mainタブのdivタブ(container workspace)の中) - ローディング表示のdivタグ
<div class="spinner-border d-none uploadFileLoading"></div>
を配置 - メディアタグ、ローディングタグをdivタグ
<div class="upload">・・・</div>
で括る
work.jsp
<main>
<div class="container workspace">
・
・
・
<hr/>
<div class="upload">
<p>アップロードファイルを表示してみる</p>
<c:if test="${!empty resultDto.filePath}">
<!-- 追加するのは以下の行のみ class="spinner-border" がローディングの画像になる -->
<div class="spinner-border d-none uploadFileLoading"></div>
<!-- 画像アップロードのとき ※どっちかのみ残す -->
<img class="uploadFile" src="<c:url value="${resultDto.filePath}" />" />
<!-- 動画(・音声)アップロードのとき ※どっちかのみ残す -->
<video class="uploadFile" src="<c:url value="${resultDto.filePath}" />" controls></video>
</c:if>
</div>
</div>
</main>
XX-2. JavaScript にアップロードファイル更新の処理を追加
-
/java-webapp-clump/src/main/webapp/assets/script.js
を修正・追記 - html 読込時の処理 に function(メソッド)呼び出しを追加
applyUploadFileWait();
- function(メソッド) ファイル更新待ち設定
applyUploadFileWait()
作成 - function(メソッド) ファイル更新
updateSrc(dom)
作成 - function(メソッド) ファイル表示
loadSrc(dom, domLoading)
作成
script.js
・
・
/**
* html 読込時の処理
*/
window.addEventListener('load', (e) => {
pageLinks.forEach((links, i) => {
applyNavbar(links);
applyCarousel(links, i);
});
// 追加するのは下の行のfunction(メソッド)呼び出し
applyUploadFileWait();
});
・
・
// function(メソッド)を追加
/**
* アップロードファイル更新待ち設定
*/
function applyUploadFileWait() {
document.querySelectorAll('.upload').forEach(uploadDom => {
let dom = uploadDom.querySelector('.uploadFile');
if (!dom || !['IMG', 'VIDEO', 'AUDIO'].includes(dom.tagName)) return;
let domLoding = uploadDom.querySelector('.uploadFileLoading');
dom.onerror = () => updateSrc(dom);
if (dom.tagName == 'IMG') {
dom.onload = () => loadSrc(dom, domLoding);
} else {
dom.onloadedmetadata = () => loadSrc(dom, domLoding);
}
dom.classList.add('d-none');
domLoding.classList.remove('d-none');
updateSrc(dom);
});
}
/**
* ファイル更新
*
* @param dom
* メディアDOM(img, video など)
*/
function updateSrc(dom) {
let src = dom.src;
dom.src = '';
dom.src = src;
}
/**
* ファイル表示
*
* @param dom
* メディアDOM(img, video など)
* @param domLoding
* ローディングDOM
*/
function loadSrc(dom, domLoding) {
domLoding.classList.add('d-none');
dom.classList.remove("d-none");
}
XX-3. ここまでやったら動作確認
- http://localhost:8080/java-wabapp-clump/web_app_work をブラウザで表示
- ファイルを選択して送信を実行
- ローディングが表示されてアップロードファイルがそのうち表示されるはず
ここから先はご自由に!
画像、動画、音声を分けて登録できるようにするとかでそれっぽくなりそう
いれたやつの一覧表示とか...
JSP, Servlet 使ってファイルアップロード(ファイル保存せず表示)
ファイルを保存せずに直接、ファイルを img タグに表示する方法
1. JSP 作成
- ファイルアップロード
form action="url_path1" method="post" enctype="multipart/form-data"
- ファイル表示
<img src="url_path2" />
アップロード・ファイル表示
<form action="url_upload" method="post" enctype="multipart/form-data">
<label>ファイル:</label>
<input type="file" name="file1" required />
<input type="submit" />
</form>
<hr/>
<img src="url_image" />
<hr/>
2. Servlet 作成
- ファイルアップロード:画像を
byte[]
にする - ファイル表示:
response.setContentType("image/png");
の設定,BufferedImage
を書き込んで返す
アップロード
@WebServlet("/url_upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Part part = request.getPart("file1");
request.getSession().setAttribute("imgBytes", readAllBytes(part.getInputStream()));
doGet(request, response);
}
public byte[] readAllBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16777215];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
}
ファイル表示
@WebServlet("/url_image")
@MultipartConfig
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream inputStream = new ByteArrayInputStream((byte[]) request.getSession().getAttribute("imgBytes"));
BufferedImage img = ImageIO.read(new BufferedInputStream(inputStream));
response.setContentType("image/png");
OutputStream outputStream = response.getOutputStream();
ImageIO.write(img, "png", outputStream);
outputStream.flush();
}
}