2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Springboot csvファイル出力 (単体テスト有り)

Last updated at Posted at 2022-07-10

概要

SpringBootでcsvファイルを出力します。
csv出力機能はjackson-dataformats-textというライブラリを使います。
テストはJunit5とMockitoを使います。

成果物

ボタンを押すとcsvファイルがダウンロードされます。
image.png

csvの中身
image.png

動作環境

OS:Windows10
IDE:IntelliJ Community or CodeSpace
Javaバージョン:11(pom.xmlでバージョン変えればok、17は確認済み)
Spring bootバージョン:2.7.0

起動方法

1.githubからプロジェクトをクローンします。branchは「csv_output」を選択します。
https://github.com/RYA234/spring_boot_memo

2.src/main/java/com/example/spring_boot_memo/SpringBootMemoApplicationを実行します。
image.png

3.以下URLを開きます
http://localhost:5000/
開くと以下場面が表示されます。

image.png

プロダクトコード

MVC系

Model(データモデル)

CsvData.java
package com.example.spring_boot_memo.csv;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;
// データモデルです。

@Data
@JsonPropertyOrder({"CODE", "名前", "値段"})
public class CsvData {
    @JsonProperty("CODE")
    int code;
    @JsonProperty("名前")
    String name;
    @JsonProperty("値段")
    int price;

    public CsvData(int code, String name, int price) {
        this.code = code;
        this.name = name;
        this.price = price;
    }
}

Controller

Controller.java
package com.example.spring_boot_memo.csv;

import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@org.springframework.stereotype.Controller
public class Controller {

    @Autowired
    CsvService csvService;

    @Autowired
    DownloadHelper downloadHelper;

    @RequestMapping(value = "index", params = "OK", method = RequestMethod.GET)
    public String indexController() {
        return "index";
    }

    @RequestMapping(value = "download", method = RequestMethod.POST)
    public ResponseEntity<byte[]> download() throws IOException {
        CsvSchema csvSchema;
        List<CsvData> csvDataList = new ArrayList<>();
        CsvData csvData = new CsvData(1, "寿司", 120);
        csvDataList.add(csvData);
        HttpHeaders headers = new HttpHeaders();
        downloadHelper.addContentDisposition(headers, "日本語ファイル名.csv");
        System.out.print(csvService.getCsvHeader());

        csvSchema = csvService.getCsvHeader();
        return new ResponseEntity<>(csvService.WriteCsvText(csvDataList, csvSchema).getBytes("MS932"), headers, HttpStatus.OK);
    }

}

View

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>インデックス画面</title>
</head>
<body>
<form id="csvform" method="post" action="/download">
    <input type="hidden" name="filename"/>
    <button type="submit" name="OK">CSVを取得</button>
</form>

</body>
</html>

Service

CsvService.java
package com.example.spring_boot_memo.csv;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class CsvService {
    @Autowired
    private final CsvMapper mapper;

    @Autowired
    private CsvSchema csvSchema;

    //DI
    public CsvService(CsvMapper mapper, CsvSchema csvSchema) {
        this.csvSchema = csvSchema;
        this.mapper = mapper;
    }

    //CsvDataからCsvファイルのヘッダー情報を取得
    public CsvSchema getCsvHeader() {
        // CsvDataの@Jsonpropertyの文字列をヘッダーとして書き込む
        csvSchema = mapper.schemaFor(CsvData.class).withHeader();
        return csvSchema;
    }

    // csvファイルの内容をString型で作成します。
    // 引数のcsvDataListはデータ部分、schemaはヘッダー部分
    public String WriteCsvText(List<CsvData> csvDataList, CsvSchema csvSchema) throws JsonProcessingException {
        return mapper.writer(csvSchema).writeValueAsString(csvDataList);
    }

}


Config(Bean化する用)

jackson-dataformats-textのクラスをBean化します。

BeanConfig.java
package com.example.spring_boot_memo.csv;

import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
    @Bean
    public CsvMapper getCsvMapper() {
        return new CsvMapper();
    }

    @Bean
    public CsvSchema getCsvSchema() {
        return CsvSchema.builder().
                build();
    }
}

テストコード(Serviceのみです)

Serviceの単体テストをします。

CsvServiceTest.java
package com.example.spring_boot_memo;

import com.example.spring_boot_memo.csv.CsvData;
import com.example.spring_boot_memo.csv.CsvService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class CsvServiceTest {

    @Autowired
    CsvService csvService;

    @Test
    @DisplayName("ヘッダーのみテスト")
    void getCsvHeaderTest() {
        CsvSchema testSchema = csvService.getCsvHeader();
        String expect1 = "CODE";
        String expect2 = "名前";
        String expect3 = "値段";

        String actual1 = testSchema.column(0).getName();
        String actual2 = testSchema.column(1).getName();
        String actual3 = testSchema.column(2).getName();

        assertEquals(expect1, actual1);
        assertEquals(expect2, actual2);
        assertEquals(expect3, actual3);
    }

    @Test
    @DisplayName("Csvファイルで出力される内容確認(ヘッダーと値)")
    void getCsvHeadersTest() throws JsonProcessingException {
        List<CsvData> csvDataList = new ArrayList<>() {
            {
                add(new CsvData(2, "高級焼肉", 1200));
            }
        };
        String actual = csvService.WriteCsvText(csvDataList, csvService.getCsvHeader());
        String expect = "CODE,名前,値段\n2,高級焼肉,1200\n";
        assertEquals(expect, actual);
    }
}

参考資料

プロダクトコード:

テストコード:
テストコードは元のgithubに書かれている場合が多いので、それを参考にすると上手く実装できると気づきました。
https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-csv/2.13.2

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?