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", "プロフィール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) 송신 버튼을 누르면 파일이 다운로드됩니다.


다운로드한 파일의 내용

일본어 파일 이름 .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"

파일명, 파일의 값 모두, 일본어도 문제 없게 출력할 수 있었습니다.

좋은 웹페이지 즐겨찾기