きり丸の技術日記

技術検証したり、資格等をここに残していきます。

SpringBootでCSVダウンロードする

きり丸アドベントカレンダー2020の20記事目です。


前回の記事でCSVのアップロード処理を書きました。逆に、CSVのダウンロード処理もできるとうれしいです。

ですので、今回の記事ではCSVダウンロードします。

ゴール

  • CSVファイルをダウンロードする

f:id:nainaistar:20201206220115p:plain

環境

  • Java
    • 15
  • org.springframework.boot:spring-boot-starter-web
    • 2.4.0
  • (org.springframework.boot:spring-boot-starter-security)
    • 2.4.0(重要ではないですが、検証ソースで使っているので…)
  • (Lombok)

手順

HTMLでファイルダウンロードボタンを作る


今回は、actionのURLがそのままファイル名となるように作っているので、ログインしている情報からuserIdを取得します。

ログインユーザーは、kirimaruとadminを用意しているので、実際のactionのURLは「/kirimaru.csv」か「admin.csv」になることを想定しています。

   <form method="get" th:action="|/${#authentication.principal.username}.csv|">
        <input type="submit" name="download_file" value="ファイルをダウンロード">
        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
    </form>>

CSVファイル用のDTOを用意する


@JsonPropertyで出力したいCSVファイルのカラム名を指定します。

@JsonPropertyOrderを付けることで、確実にcsvファイルの出力される順番が保証されるので、書くべきでしょう。

@Value
@AllArgsConstructor
@JsonPropertyOrder({"ID", "UserId", "Action"})
public class TodoCsv {
  @JsonProperty("ID")
  private long id;
  @JsonProperty("UserId")
  private String userId;
  @JsonProperty("Action")
  private String action;

}

DBから取得した値を元にCSVファイルをダウンロードする


@GetMappingのvalueがそのままファイル名となります。producesに文字コード等を設定します。

今回の処理で大事なのは次の処理です。他の項目はアドベントカレンダーとしては必要ですが、この記事だけを見に来た人にとっては蛇足になります。

    CsvMapper mapper = new CsvMapper();
    CsvSchema schema = mapper.schemaFor(TodoCsv.class).withHeader();
    return mapper.writer(schema).writeValueAsString(csvs);

ファイル名:IndexController.java

  @GetMapping(value = "/*.csv", params = "download_file",
      produces = MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8; Content-Disposition: attachment"
  )
  @ResponseBody
  public Object index() throws JsonProcessingException {
    // User名取得
    SecurityContext securityContext = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
    Authentication authentication = securityContext.getAuthentication();
    AuthTargetUser principal = (AuthTargetUser) authentication.getPrincipal();
    String username = principal.getUsername();
    // DBから取得
    List<TodoDto> todos = todoRepository.findList(username);

    // CSVファイル用のDTOに詰め直す
    List<TodoCsv> csvs = todos.stream().map(
        e -> new TodoCsv(e.getId(), e.getUserId(), e.getAction())
    ).collect(Collectors.toList());
    // ファイルをダウンロードさせる
    CsvMapper mapper = new CsvMapper();
    CsvSchema schema = mapper.schemaFor(TodoCsv.class).withHeader();
    return mapper.writer(schema).writeValueAsString(csvs);
  }}

ソースコード

アドベントカレンダー20日目。
github.com

終わりに

アップロードと比べてダウンロードが非常に面倒でした。まさかCSVファイル用に別のライブラリを入れる必要があったとは…。

正直、「参考記事をやってみた」以上の情報が無いので、もっと詳しいことは参考記事の先を見ていただけると分かります。追加情報としては、2020年でも動くよ―程度ですね。

普段触っていない機能は理解が難しいです。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

参考記事

敬称略

yo1000:Spring MVC で CSV をダウンロードさせる qiita.com

類似記事

きり丸アドベントカレンダー2020 adventar.org

きり丸のHerokuページ
https://kirimaru-todoapp.herokuapp.com/

21日目のアドベントカレンダーの記事 nainaistar.hatenablog.com

f:id:nainaistar:20201109133010p:plain