Springboot でCSVをダウンロード

###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", "プロフィール１", new Date()));
    	members.add(new Member(2L, "user02", "プロフィール２", new Date()));
    	members.add(new Member(3L, "user03", "プロフィール３", 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](https://qiita-image-store.s3.amazonaws.com/0/246741/8fa8bb1d-200c-2c08-8b5f-2bbc86f7a561.png)


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

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

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