Spring Boot DB連携

Spring BootのWEB画面上でファイルアップロード・ダウンロード機能を実装してみた(ソースコード編)

今回も引き続き、ファイルアップロード・ダウンロード機能の実装について述べる。ここでは、具体的なサンプルプログラムのソースコードを共有する。

前提条件

下記記事を参照のこと。

Spring BootのWEB画面上でファイルアップロード・ダウンロード機能を実装してみた(完成イメージと前提条件)前回は、Spring Bootのmybatisを利用して、「BLOB」「CLOB」を含むテーブルへのデータ追加・データ参照を行った。今回...

作成したサンプルプログラムの内容

作成したサンプルプログラムの構成は以下の通り。
プログラムの構成

なお、上図の赤枠は、下記記事に記載したソースコードと比較し、変更になったソースコードを示す。赤枠のソースコードについては今後記載する。

Spring Bootで、OracleのテーブルにBLOB,CLOBのカラムを含む場合のOracle接続を実装してみたOracleのデータ型に、大量のデータやバイナリデータを格納できる「BLOB」「CLOB」がある。「BLOB」にはバイナリデータ、「CL...

ファイルデータ(file_data)テーブルにアクセスするMapperクラスは以下の通り。今回必要なfindAllメソッド・getMaxIdメソッドを追加している。

package com.example.demo;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface FileDataMapper {

    /**
     * ファイルデータテーブル(file_data)から全件取得する
     * @return ファイルデータテーブル(file_data)のデータリスト
     */
    @Select("SELECT id, file_path as filePath, file_obj as fileObj "
            + " FROM file_data ORDER BY id asc")
    List<FileData> findAll();

    /**
     * 指定したIDをもつファイルデータテーブル(file_data)のデータを取得する
     * @param id ID
     * @return ファイルデータテーブル(file_data)の指定したIDのデータ
     */
    @Select("SELECT id, file_path as filePath, file_obj as fileObj "
            + " FROM file_data WHERE id = #{id}")
    FileData findById(Long id);

    /**
     * ファイルデータテーブル(file_data)の最大値IDを取得する
     * @return ファイルデータテーブル(file_data)の最大値ID
     */
    @Select("SELECT NVL(max(id), 0) as maxId FROM file_data")
    long getMaxId();

    /**
     * 指定したファイルデータテーブル(file_data)のデータを追加する
     * @param fileData ファイルデータテーブル(file_data)
     */
    @Insert("INSERT INTO file_data ( id, file_path, file_obj ) "
            + " VALUES ( #{id}, #{filePath}, #{fileObj} )")
    void insert(FileData fileData);
}
「CODE×CODE」は、需要の高い技術(AWS, Python等)を習得できるプログラミングスクールスクールだった近年、さまざまな会社でクラウド(特にIaaSやPaaSのパブリッククラウド)の需要が非常に高まっていて、クラウドサービスによるシステム開...

また、ファイルデータ(file_data)テーブルにアクセスするMapperクラスを利用するコントローラクラスは以下の通り。ここではファイルアップロード・ファイルダウンロード処理も記載している。

ファイルアップロード処理(addメソッド)内では引数のMultipartFileオブジェクトからファイルオブジェクトを取得後、ファイルデータテーブルへのデータ追加を行っている。また、ファイルダウンロード処理(downloadメソッド)内では指定したIDのデータ取得後、HttpServletResponseクラスのwriteメソッドでダウンロード出力を行っている。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

@Controller
public class DemoController {

    /**
     * ファイルデータテーブル(file_data)へアクセスするMapper
     */
    @Autowired
    private FileDataMapper fileDataMapper;

    /**
     * ファイルデータ一覧表示処理
     * @param model Modelオブジェクト
     * @return 一覧画面
     */
    @RequestMapping("/")
    public String index(Model model){
        //ファイルデータテーブル(file_data)を全件取得
        List<FileData> list = fileDataMapper.findAll();
        model.addAttribute("fileDataList", list);

        //一覧画面へ移動
        return "list";
    }

    /**
     * ファイルデータ登録画面への遷移処理
     * @return ファイルデータ登録画面
     */
    @PostMapping("/to_add")
    public String to_add(){
        return "add";
    }

    /**
     * ファイルデータ登録処理
     * @param uploadFile アップロードファイル
     * @return ファイルデータ一覧表示処理
     */
    @PostMapping("/add")
    @Transactional(readOnly = false)
    public String add(@RequestParam("upload_file") MultipartFile uploadFile){
        //最大値IDを取得
        long maxId = fileDataMapper.getMaxId();

        //追加するデータを作成
        FileData fileData = new FileData();
        fileData.setId(maxId + 1);
        fileData.setFilePath(uploadFile.getOriginalFilename());
        try{
            fileData.setFileObj(uploadFile.getInputStream());
        }catch(Exception e){
            System.err.println(e);
        }
        //1件追加
        fileDataMapper.insert(fileData);

        //一覧画面へ遷移
        return "redirect:/to_index";
    }

    /**
     * 追加完了後に一覧画面に戻る
     * @param model Modelオブジェクト
     * @return 一覧画面
     */
    @GetMapping("/to_index")
    public String toIndex(Model model){
        return index(model);
    }

    /**
     * ファイルダウンロード処理
     * @param id ID
     * @param response HttpServletResponse
     * @return 画面遷移先(nullを返す)
     */
    @RequestMapping("/download")
    public String download(@RequestParam("id") String id
            , HttpServletResponse response){
        //ダウンロード対象のファイルデータを取得
        FileData data = fileDataMapper.findById(Long.parseLong(id));

        //ファイルダウンロードの設定を実施
        //ファイルの種類は指定しない
        response.setContentType("application/octet-stream");
        response.setHeader("Cache-Control", "private");
        response.setHeader("Pragma", "");
        response.setHeader("Content-Disposition"
                ,"attachment;filename=\"" + getFileName(data.getFilePath()) + "\"");

        //ダウンロードファイルへ出力
        try(OutputStream out = response.getOutputStream();
            InputStream in = data.getFileObj()){
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = in.read(buff, 0, buff.length)) != -1) {
                out.write(buff, 0, len);
            }
            out.flush();
        }catch(Exception e){
            System.err.println(e);
        }

        //画面遷移先はnullを指定
        return null;
    }

    /**
     * ファイルパスからファイル名を取得する
     * @param filePath ファイルパス
     * @return ファイル名
     */
    private String getFileName(String filePath){
        String fileName = "";
        if(filePath != null && !"".equals(filePath)){
            try{
                //ファイル名をUTF-8でエンコードして指定
                fileName = URLEncoder.encode(new File(filePath).getName(), "UTF-8");
            }catch(Exception e){
                System.err.println(e);
                return "";
            }
        }
        return fileName;
    }

}
サラリーマン型フリーランスSEという働き方でお金の不安を解消しよう先日、「サラリーマン型フリーランスSE」という働き方を紹介するYouTube動画を視聴しましたので、その内容をご紹介します。 「サ...

さらに、一覧画面・入力画面のソースコード内容は以下の通り。ファイルアップロードを行うファイルの選択は、inputタグのtype=”file”で指定していて、nameタグの内容をコントローラクラスの引数のMultipartFileオブジェクトとして渡している。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>一覧画面</title>
</head>
<body>
ファイルデータテーブル(file_data)の全データ<br/><br/>

<table border="1" cellpadding="5">
    <tr>
        <th>ID</th>
        <th>ファイルパス</th>
        <th></th>
    </tr>
    <tr th:each="obj : ${fileDataList}">
        <td th:text="${obj.id}"></td>
        <td th:text="${obj.filePath}"></td>
        <td>
            <!-- ダウンロードボタンを表示 -->
            <form action="#" method="get"
                  th:action="@{/download(id=${'__${obj.id}__'})}"
                  th:method="download" >
                <input type="hidden" name="_method" value="download" />
                <input type="submit" value="ダウンロード" />
            </form>
        </td>
    </tr>
</table>
<br/><br/>
<form method="post" th:action="@{/to_add}">
    <input type="submit" value="データ追加" /><br/><br/>
    <input type="button" value="閉じる" onclick="window.close();" />
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>入力画面</title>
</head>
<body>
<p>入力ファイルを指定し、「登録」ボタンを押下してください。</p><br/>

<form method="post" enctype="multipart/form-data" th:action="@{/add}">
    ファイル : <input type="file" name="upload_file" /><br/><br/>
    <input type="submit" value="送信" />
    <input type="button" value="戻る" onclick="history.back();" />
</form>
</body>
</html>

その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-upload-download-2/demo

要点まとめ

  • ファイルアップロード処理では、HTMLファイルでinputタグのtype=”file”を指定し、nameタグの内容をコントローラクラスの引数のMultipartFileオブジェクトとして渡すことで、ファイルオブジェクトを連携できる。
  • ファイルダウンロード処理では、HttpServletResponseオブジェクトのwriteメソッドで、ダウンロード出力処理を行えばよい。