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

Springboot でCSVをダウンロード

More than 1 year has passed since last update.

SpringbootでCSVをダウンロードしてみます。日本語にも対応します。

1.依存関係

build.gradle
dependencies {
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.webjars:jquery:3.3.1')
    compile('com.fasterxml.jackson.dataformat:jackson-dataformat-csv');
    runtime('org.springframework.boot:spring-boot-devtools')
    compileOnly('org.projectlombok:lombok')
    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

jackson-dataformat-csvを使います

2.Helper

ダウンロードするときに、ファイル名を日本語に対応するためのヘルパークラスを作成します。

DownloadHelper.java
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriUtils;

@Component
public class DownloadHelper {
    private static final String CONTENT_DISPOSITION_FORMAT
         = "attachment; filename=\"%s\"; filename*=UTF-8''%s";
    public void addContentDisposition(HttpHeaders headers, String fileName)
            throws UnsupportedEncodingException {
        String headerValue = String.format(CONTENT_DISPOSITION_FORMAT,
                fileName, UriUtils.encode(fileName, StandardCharsets.UTF_8.name()));
        headers.add(HttpHeaders.CONTENT_DISPOSITION, headerValue);
    }

}

3.ダウンロードするデータ

Member.java
import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import lombok.Data;

@JsonPropertyOrder({"ID", "名前", "プロフィール", "更新日時"})
@Data
public class Member {
    @JsonProperty("ID")
    private Long id;
    @JsonProperty("名前")
    private String name;
    @JsonProperty("プロフィール")
    private String desc;
    @JsonProperty("更新日時")
    @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss")
    private Date modified;

    public Member() {}

    public Member(Long id, String name, String desc, Date modified) {
        this.id = id;
        this.name = name;
        this.desc = desc;
        this.modified = modified;
    }
}

4.Controller

CsvController.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.csv.CsvGenerator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

@Controller
public class CsvController {

    @Autowired
    DownloadHelper downloadHelper;

    /**
     * CsvMapperで、csvを作成する。
     * @return csv(String)
     * @throws JsonProcessingException
     */
    public String getCsvText() throws JsonProcessingException {
        CsvMapper mapper = new CsvMapper();
        //文字列にダブルクオートをつける
        mapper.configure(CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS, true);
        //ヘッダをつける
        CsvSchema schema = mapper.schemaFor(Member.class).withHeader();
        //メンバーデータをダウンロードするイメージ。本来はDBからデータを取得する。
        List<Member> members = new ArrayList<Member>();
        members.add(new Member(1L, "user01", "プロフィール1", new Date()));
        members.add(new Member(2L, "user02", "プロフィール2", new Date()));
        members.add(new Member(3L, "user03", "プロフィール3", new Date()));
        return mapper.writer(schema).writeValueAsString(members);
    }

    /**
     * csvをダウンロードする。
     * @param response
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/download/csv", method = RequestMethod.POST)
    public ResponseEntity<byte[]> download() throws IOException {
        HttpHeaders headers = new HttpHeaders();
        downloadHelper.addContentDisposition(headers, "日本語ファイル名.csv");
        return new ResponseEntity<>(getCsvText().getBytes("MS932"), headers, HttpStatus.OK);
    }
}

5.HTML

index.html
<!DOCTYPE html>
<html lang="ja" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script th:src="@{/webjars/jquery/3.3.1/jquery.min.js}"></script>
</head>
<body>
<form id="csvform" method="post" th:action="@{/download/csv}">
    <input type="hidden" name="filename"/>
    <button type="submit">送信</button>
</form>
<script>
</script>
</body>
</html>

Postするだけのformです。

6.確認

(1)送信ボタンを押すと、ファイルがダウンロードされる。
image.png

ダウンロードしたファイルの内容

日本語ファイル名.csv
"ID","名前","プロフィール","更新日時"
1,"user01","プロフィール1","2018/09/24 07:28:57"
2,"user02","プロフィール2","2018/09/24 07:28:57"
3,"user03","プロフィール3","2018/09/24 07:28:57"

ファイル名、ファイルの値ともに、日本語も問題なく出力できました。

t-iguchi
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