10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Java】ファイルをアップロードして中身をDBに登録したい

Posted at

はじめに

今回は画面からcsvファイルをアップロードし、ファイル内のデータをDBに登録する処理を作ってみます。初学者の方にとって少しでも参考になれば幸いです。

環境

windows11
Java 21
Spring Boot 3.4.1
Maven 3.9.9
Thymeleaf 3.1.3
こちらを参考にしていただければ同じ環境の構築が可能です。

アップロード

まずは、画面からファイルをアップロードし任意のフォルダに保存しておく処理を作ります。

  • uploadForm.html
    画面側ではファイルを選択してアップロードボタンを押すだけの簡素な作りにしています。
    アップロードの結果が分かるようにmessageの値を表示します。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ファイルアップロード</title>
</head>
<body>
	<div><h2>ファイルアップロード</h2></div>
	
	<div>
		<!-- アップロードフォーム -->
		<form action="/upload" method="post" enctype="multipart/form-data">
			<label for="file">ファイルを選択:</label>
		    <input type="file" id="file" name="file" required>
		    <button type="submit">アップロード</button>
		</form>
	</div>
	
	<div th:if="${message}">
		<p th:text="${message}"></p>
	</div>
</body>
</html>
  • FileUploadController.java
    ファイルを任意のフォルダに格納する処理です。
    あとから少し処理は変える予定ですが一旦ここまでで動作確認して問題ないことを確認します。
package com.example.file.controller;

import java.io.File;

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.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class FileUploadController {

	@GetMapping("/")
    public String showUploadForm() {
        return "uploadForm";
    }
	
	@PostMapping("/upload")
    public String fileUploadFile(@RequestParam("file") MultipartFile file, Model model) {
        
		try {
			// ファイルを保存する場所
            String uploadDir = "任意のパス";

            // 保存するファイルのパスを生成
            File dest = new File(uploadDir + file.getOriginalFilename());
            file.transferTo(dest);
			
			model.addAttribute("message", "ファイルがアップロードされました");
		} catch (Exception e) {
			model.addAttribute("message", "ファイルアップロードに失敗しました");
		}
		
		return "uploadForm";
    }
}

ファイルの読み込みと登録

実際にファイルの中身を読み込み、データを登録する処理を追加していきます。

  • FileUploadController.java
package com.example.file.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.example.file.service.FileUploadService;

@Controller
public class FileUploadController {
	
	@Autowired
	FileUploadService fileUploadService;
	

	@GetMapping("/")
    public String showUploadForm() {
        return "uploadForm";
    }
	
	@PostMapping("/upload")
    public String fileUploadFile(@RequestParam("file") MultipartFile file, Model model) {
        
		try {
			String message = fileUploadService.uploadFile(file);
			
			model.addAttribute("message", message);
		} catch (Exception e) {
			logger.error(e.getMessage());
			model.addAttribute("message", "ファイルアップロードに失敗しました");
		}

		return "uploadForm";
    }
}
  • FileUploadServiceImpl.java
package com.example.file.service.impl;

import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.example.file.logic.CSVFileUploadLogic;
import com.example.file.service.FileUploadService;


@Service
public class FileUploadServiceImpl implements FileUploadService {
	
	@Autowired
	private CSVFileUploadLogic csvFileUploadLogic;
	
	@Override
	public String uploadFile(MultipartFile file)  throws IllegalStateException, IOException {
		
		if (!csvFileUploadLogic.validateCSVFile(file))
			return "ファイルが正しくありません";
		
		csvFileUploadLogic.regist(file);
		
		csvFileUploadLogic.upload(file);
		
		return "完了";
	}
}
  • CSVFileUploadLogicImpl.java
    実際にファイルの中身を読み込んでDBに登録する処理を実装しました。
    アップロードするメソッドと分けています。
    ファイルのバリデート処理はダミーです。
package com.example.file.logic.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.example.file.logic.CSVFileUploadLogic;
import com.example.file.mapper.TestMapper;
import com.example.file.model.Test;

@Component
public class CSVFileUploadLogicImpl implements CSVFileUploadLogic {
	
	@Autowired
	private TestMapper testMapper;
	
	@Override
	public boolean validateCSVFile(MultipartFile file) {
		return true;
	}
	
	@Override
	public void regist(MultipartFile file) throws IOException {
		
		InputStreamReader inputStream = new InputStreamReader(file.getInputStream());
		BufferedReader bufferedReader = new BufferedReader(inputStream);
		
		String line;

        // ヘッダー行は登録対象外
		boolean firstLine = true;
        // 登録するデータ格納用リスト
		List<Test> testList = new ArrayList<>();

        // 1行ずつ読み込み
		while ((line = bufferedReader.readLine()) != null) {
			if (firstLine) {
                firstLine = false;
                continue;
            }
			
			String[] colData = line.split(",");
			
			Test test = new Test();
			test.setComment(colData[0]);
			test.setRegistUser(colData[1]);
			testList.add(test);
		}
		// Mapper呼び出し
		testMapper.regist(testList);
	}
	
	@Override
	public void upload(MultipartFile file) throws IllegalStateException, IOException {
		// ファイルを保存する場所
        String uploadDir = "任意のパス";

        // 保存するファイルのパスを生成
        File dest = new File(uploadDir + file.getOriginalFilename());
        file.transferTo(dest);
	}
}


  • Test.java
    Dataアノテーションを利用することでgetter/setterを自動生成してくれます。
package com.example.file.model;

import lombok.Data;

@Data
public class Test {
	
	private int id;
    private String comment;
    private String registUser;
}
  • TestMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//MyBatis//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.file.mapper.TestMapper">
    <insert id="regist">
        INSERT INTO TestTable(comment, registuser) VALUES
        <foreach collection="list" item="test" index="index" separator=",">
            (#{test.comment}, #{test.registUser})
        </foreach>
    </insert>
</mapper>

動作確認

画面からアップロードしてみます。
カンマ区切りのcsvファイルを作りました。
動作確認4.png

画面を開いてファイルを選択した状態がこちらです。
動作確認2.png

アップロードボタンを押下すると「完了」というメッセージが表示されました。
動作確認3.png

事前の確認の影響で、idが途中から採番されていますがデータの登録ができています。
動作確認5.png

あとがき

最後まで読んでいただきありがとうございます。

今回はファイルの保存とデータを登録する処理だけでしたので、目を瞑ったところだけ書き残しておきます。

  • パスはプロパティファイルなどで管理
  • アップロードするファイルのエラーチェック
    拡張子、ファイルサイズ、ヘッダー行の有無、項目数、桁数など
  • コントローラに丸投げしている例外
10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?