Help us understand the problem. What is going on with this article?

Spring Bootでファイルアップロードを行う

■環境

Spring Boot 1.2.5.Release
Java 8
Maven 3.3.1

■概要

Spring Bootで画面からアップロードしたファイルをサーバー側に置くまでの手順を解説します。
※クライアントのWebブラウザはIE9以下では動きません

■pom.xml

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から。

data_upload_view.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送信してます。

data_upload_view.js
// 主処理部
$(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以下では動きません。

最後にサーバー側の処理です。

FileUploadRestController.java
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'ってなんだ?

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away