■環境
Spring Boot 1.2.5.Release
Java 8
Maven 3.3.1
■概要
Spring Bootで画面からアップロードしたファイルをサーバー側に置くまでの手順を解説します。
※クライアントのWebブラウザはIE9以下では動きません
■pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ■Spring Boot本体 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<!-- ■Spring Boot関連 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- ■フロントエンドフレームワーク -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
■詳細
まずはHTMLから。
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>一括アップロード</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="stylesheet" href="./webjars/bootstrap/3.3.1/css/bootstrap.min.css" type="text/css"></link>
<!--[if lt IE 9]>
<script type="text/javascript" src="./javascript/ie8/html5shiv.js"></script>
<script type="text/javascript" src="./javascript/ie8/respond.js"></script>
<script type="text/javascript" src="./javascript/ie8/jquery-1.11.3.min.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script type="text/javascript" src="./webjars/jquery/2.1.4/jquery.min.js"></script>
<!--<![endif]-->
<script type="text/javascript" src="./webjars/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="./javascript/data_upload_view.js"></script>
<script type="text/javascript" src="./javascript/common.js"></script>
<script type="text/javascript" src="./javascript/datetimepicker/jquery.datetimepicker.js"></script>
</head>
<body>
<div class="container">
<!-- タイトル部 -->
<div class="row">
<p><h1 id="title">一括アップロード</h1></p>
</div>
<!-- ヘッダー部 -->
<div class="row">
<!-- パンくずリスト -->
<div class="col-md-4 col-lg-4">
<ul class="breadcrumb">
<li><a href="menu">Menu</a></li>
<li class="active">一括アップロード</li>
</ul>
</div>
<div class="col-md-4 col-lg-4"></div>
<div class="col-md-4 col-lg-4"></div>
</div>
<!-- ファイル情報部 -->
<div class="row">
<div class="col-md-2 col-lg-2"></div>
<div class="col-md-8 col-lg-8">
<div class="well well-sm">
<div>アップロードするファイルを選択して、アップロードボタンを押下してください。</div>
<br />
<form id="data_upload_form" enctype="multipart/form-data" method="post">
<div class="form-group">
<label>■ファイル種類:</label>
<select id="select_file_type" name="select_file_type" required="">
<option value="login-user">ログインユーザー</option>
<!-- アップロードするファイルを定義していく -->
</select>
</div>
<div class="form-group">
<label>■ファイルパス:</label>
<input type="file" id="upload_file" name="upload_file" required="" />
</div>
<div class="form-group">
<input id="data_upload_button" type="submit" value="アップロード" />
</div>
</form>
</div>
</div>
<div class="col-md-2 col-lg-2"></div>
</div>
</div>
</body>
</html>
特別なことはしておりませんが、あえてポイントを挙げるとすれば以下でしょうか。
<form id="data_upload_form" enctype="multipart/form-data" method="post">
enctype="multipart/form-data"
というのがポイントでこれでアップロードされたファイルをサーバー側に送信することができます。
サーバーへの送信はJavaScriptでajax送信してます。
// 主処理部
$(function(){
// アップロードボタンを押下した
$("#data_upload_form").submit(function(event){
// 要素規定の動作をキャンセルする
event.preventDefault();
var ajaxUrl = "file/upload?";
// ファイル種類
ajaxUrl += "filetype=" + $("#select_file_type option:selected").val();
if(window.FormData){
var formData = new FormData($(this)[0]);
$.ajax({
type : "POST", // HTTP通信の種類
url : ajaxUrl, // リクエストを送信する先のURL
dataType : "text", // サーバーから返されるデータの型
data : formData, // サーバーに送信するデータ
processData : false,
contentType: false,
}).done(function(data) { // Ajax通信が成功した時の処理
alert("アップロードが完了しました。");
}).fail(function(XMLHttpRequest, textStatus, errorThrown) { // Ajax通信が失敗した時の処理
alert("アップロードが失敗しました。");
});
}else{
alert("アップロードに対応できていないブラウザです。");
}
});
});
}
ポイントは2つです。
// 要素規定の動作をキャンセルする
event.preventDefault();
①submit規定の動作をキャンセルさせることでJavascript内で独自の動作を定義します。
var formData = new FormData($(this)[0]);
②formの中身をそのままFormDataオブジェクトにぶち込みます。
FormDataはIE9以下では動きません。
最後にサーバー側の処理です。
package com.sample.fileupload.controller;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import com.sample.login.service.data.LoginUser;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 一括アップロードのコントローラー
*/
@RestController
@RequestMapping("file/upload")
public class FileUploadRestController {
/**
* 一括アップロードを行う
*
* @param multipartFile
* @param fileType
* @param registrationType
* @param dailyAttendanceYyyymm
* @param loginUser
* @return
*/
@RequestMapping(method = RequestMethod.POST)
public Object post(
@RequestParam("upload_file") MultipartFile multipartFile,
@RequestParam("filetype") String fileType, // ファイル種類
@AuthenticationPrincipal LoginUser loginUser){ // 認証ユーザー情報
// ファイルが空の場合は異常終了
if(multipartFile.isEmpty()){
// 異常終了時の処理
}
// ファイル種類から決まる値をセットする
StringBuffer filePath = new StringBuffer("/uploadfile")
.append(File.separator).append(fileType); //ファイルパス
// アップロードファイルを格納するディレクトリを作成する
File uploadDir = mkdirs(filePath);
try {
// アップロードファイルを置く
File uploadFile =
new File(uploadDir.getPath() + "/" + fileType);
byte[] bytes = multipartFile.getBytes();
BufferedOutputStream uploadFileStream =
new BufferedOutputStream(new FileOutputStream(uploadFile));
uploadFileStream.write(bytes);
uploadFileStream.close();
return "You successfully uploaded.";
} catch (Exception e) {
// 異常終了時の処理
} catch (Throwable t) {
// 異常終了時の処理
}
}
/**
* アップロードファイルを格納するディレクトリを作成する
*
* @param filePath
* @return
*/
private File mkdirs(StringBuffer filePath){
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
File uploadDir = new File(filePath.toString(), sdf.format(now));
// 既に存在する場合はプレフィックスをつける
int prefix = 0;
while(uploadDir.exists()){
prefix++;
uploadDir =
new File(filePath.toString() + sdf.format(now) + "-" + String.valueOf(prefix));
}
// フォルダ作成
uploadDir.mkdirs();
return uploadDir;
}
}
アップロードされたファイルは「org.springframework.web.multipart.MultipartFile」で受け取ります。
@RequestParam("upload_file") MultipartFile multipartFile,
受け取ったファイルはStream系のクラスで読み込んでサーバーに置きます。
File uploadFile =
new File(uploadDir.getPath() + "/" + fileType);
byte[] bytes = multipartFile.getBytes();
BufferedOutputStream uploadFileStream =
new BufferedOutputStream(new FileOutputStream(uploadFile));
uploadFileStream.write(bytes);
uploadFileStream.close();
■まとめ
・クライアント側からFormでファイルをアップロードする
・enctype="multipart/form-data"とすることでファイルとしてサーバー側に送れる
・Formの中身をそのままFormDataオブジェクトにぶち込みajax送信
・サーバー側ではMultipartFileで受け取る
■参考資料
Spring Bootでファイルをアップロードする
enctype='multipart/form-data'ってなんだ?