[Spring Boot] Spring Boot에서 csv 파일 생성 및 다운로드 API 작성 (with. React)

Sungjin Cho·2024년 7월 30일
0

Spring Boot

목록 보기
9/15
post-thumbnail

Spring Boot + react csv 파일 생성 및 다운로드

사용자를 위해 클라이언트에서 만들어진 데이터를 csv 파일로 만들어 다운로드 가능하게 하기 위해서는 어떻게 해야 할까?

프로젝트 적용

큰 흐름은 아래와 같다.

  1. 데이터를 가공하여 csv 형태로 생성
  2. 가공한 csv 데이터를 request body에 담아 api 요청
  3. json으로 받은 csv 데이터를 csv 파일로 변환 후 response body에 담아 전달
  4. response body를 blob 객체로 변환 후 브라우저의 메모리 url 객체를 생성
  5. 다운로드

  <button
  onClick={onCsvownload}
  style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    padding: 0,
  }}
>
  <RiFileExcel2Line size={24} style={{ color: "green" }} />
</button>

위와 같은 테이블이 있고 우측 상단에 excel 아이콘을 누르면 테이블의 내용을 저장하고자 한다.

그럼 예제 코드를 살펴보자.

 const onCsvDownload = async () => {
    try {
      const csvData = [
        [
          "No",
          "Pos Invoice No",
          "Amount",
          "Tax",
          "VAT",
          "Cash Amount",
          "Card Amount",
          "Order Time",
          "Buy Type",
        ],
        ...ordersData.map((item, index) => [
          index + 1,
          item.pos_invoice_no,
          item.amount,
          item.tax,
          item.vat,
          item.od_cash_amount,
          item.od_card_amount,
          item.od_time,
          convertBuyType(item.buyType),
        ]),
      ];
      console.log("csvData", csvData);
      console.log("json", JSON.stringify(csvData));

      const config = {
        method: "post",
        url: "/api2/csv",
        data: {
          csv_data: csvData,
          file_name: `orders_${activeOrderTab}_${selectedDate}.csv`,
        },
        responseType: "blob",
      };

      const response = await axios.request(config);

      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement("a");
      link.href = url;
      link.setAttribute(
        "download",
        `orders_${activeOrderTab}_${selectedDate}.csv`
      );
      document.body.appendChild(link);
      link.click();
      link.remove();
    } catch (error) {
      console.error("Error downloading Excel:", error);
      if (error.response) {
        console.error("Response data:", error.response.data);
        console.error("Response status:", error.response.status);
      }
    }
  }
  • window.URL.createObjectURL(new Blob([response.data])): 서버로부터 받은 응답 데이터를 Blob 객체로 변환한 후, 브라우저의 메모리에 URL 객체를 생성한다.
  • const link = document.createElement("a");: a 태그를 동적으로 생성한다.
  • link.href = url;: 생성한 URL 객체를 a 태그의 href 속성에 할당한다.
  • link.setAttribute("download", "filename.csv");: download 속성을 설정하여 파일 이름을 지정한다.
  • document.body.appendChild(link);: a 태그를 문서에 추가한다.
  • link.click();: 파일 다운로드를 트리거한다.
  • link.remove();: 다운로드 후 a 태그를 문서에서 제거한다.
//controller.java

 @PostMapping("/csv")
  public ResponseEntity<InputStreamResource> downloadCsv(@RequestBody ExcelDownloadRequestDto request) {
      ByteArrayInputStream byteArrayInputStream = taxExcelService.generateCsv(request.csvData());

      HttpHeaders headers = new HttpHeaders();
      headers.add("Content-Disposition", "attachment; filename=" + request.fileName());

      return ResponseEntity
              .ok()
              .headers(headers)
              .contentType(MediaType.parseMediaType("text/csv"))
              .body(new InputStreamResource(byteArrayInputStream));

  }
  • ByteArrayInputStream byteArrayInputStream = taxExcelService.generateCsv(request.csvData());: generateCsv 메서드를 호출하여 CSV 데이터를 바이트 배열로 변환한다.
  • HttpHeaders headers = new HttpHeaders();: HTTP 헤더를 설정한다.
  • headers.add("Content-Disposition", "attachment; filename=" + request.fileName());: 파일 이름을 지정하여 다운로드를 위한 헤더를 추가한다.
  • return ResponseEntity.ok().headers(headers).contentType(MediaType.parseMediaType("text/csv")).body(new InputStreamResource(byteArrayInputStream));: HTTP 200 응답과 함께 CSV 파일 데이터를 반환한다.
//service.java

public ByteArrayInputStream generateCsv(List<List<String>> data) {
  try {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      CSVPrinter csvPrinter = new CSVPrinter(new PrintWriter(out), CSVFormat.DEFAULT);

      for (List<String> record : data) {
          csvPrinter.printRecord(record);
      }

      csvPrinter.flush();
      return new ByteArrayInputStream(out.toByteArray());
  } catch (IllegalArgumentException e) {
      log.error("Error generating CSV: {}", e.getMessage());
      throw e;
  } catch (IOException e) {
      log.error("Error generating CSV: {}", e.getMessage());
      throw new RuntimeException("Failed to generate CSV file: " + e.getMessage());
  }
}
  • generateCsv: CSV 데이터를 받아서 바이트 배열로 변환하는 메서드이다.
  • CSVPrinter csvPrinter = new CSVPrinter(new PrintWriter(out), CSVFormat.DEFAULT);: CSV 프린터를 생성하여 데이터를 작성한다.
  • csvPrinter.printRecord(record);: 데이터를 순회하며 CSV 레코드를 작성한다.

이제 버튼을 클릭해보면 설정한 파일명이 다운로드에 나타나고

작성한 csv 파일 내용을 확인할 수 있다.

0개의 댓글