가수면

파일 다운로드 기능 API 구현 본문

Java

파일 다운로드 기능 API 구현

니비앙 2024. 8. 13. 13:15

프론트에서 파일을 다운받기 위해 백엔드로 요청 보낼 때 백엔드에서 구성해야할 로직을 정리한다.

백엔드 (JAVA)

    public void downloadFile(HttpServletResponse response,
                             String fileOriginNm,
                             String policyFileNm,
                             String policyFlpth) {
                             
        String uploadPath = policyFileService.getPolicyUploadFile(policyFlpth, policyFileNm);	// uploadPath: WEB-INF/files/policy/upload/cisa_5g_strategy_508_1672216004129.pdf
        File file = new File(uploadPath);

        if (!file.exists()) {
            throw new CustomException("File not found: " + fileOriginNm);
        }

        try {
            String mimeType = URLConnection.guessContentTypeFromName(file.getName());   // 파일 이름을 기반으로 MIME 타입(파일의 콘텐츠 유형)을 추정
            if (mimeType == null) {
                mimeType = "application/octet-stream";
            }
            response.setContentType(mimeType);
            String encodedFileName = URLEncoder.encode(fileOriginNm, StandardCharsets.UTF_8).replaceAll("\\+", "%20");	// 한글명, 특수문자 인코딩
            response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", encodedFileName));
            response.setContentLength((int) file.length());
            @Cleanup    // InputStream, Reader와 같은 자원은 사용 후 반드시 닫아야 하는데, 이 과정을 Lombok으로 자동화
            // InputStream - Java에서 데이터를 바이트 단위로 읽어들이기 위한 최상위 추상 클래스(FileInputStream를 통해 구현). 네트워크 소켓 등에서 데이터를 읽을 때 사용
            // FileInputStream - 파일로부터 바이트 스트림을 읽어 파일을 열고, 그 내용을 InputStream을 통해 읽음
            // BufferedInputStream - 작은 바이트 단위로 여러 번 읽는 대신, 버퍼(일정 크기의 메모리 공간)를 사용하여 한 번에 더 많은 데이터를 읽어 입출력 성능이 향상
            InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
            // 파일이나 스트림 간의 복사를 간단하게 수행. copy(InputStream in, OutputStream out) 메서드는 주어진 입력 스트림(in)에서 데이터를 읽어, 주어진 출력 스트림(out)으로 데이터를 복사
            FileCopyUtils.copy(inputStream, response.getOutputStream());
        } catch (IOException e) {
            throw new CustomException("File not found: " + fileOriginNm);
        }

    }

- 코드 실행 과정 -

  1. 파일 준비: uploadPath로 프로젝트 내 위치한 파일 경로를 가져와 파일 객체로 생성
  2. 응답 설정 세팅: response에 필요한 타입, 헤더 등을 설정
  3. FileInputStream을 통해 파일 열기: new FileInputStream(file)으로 파일을 열고, 이 파일에서 데이터를 읽어들일 수 있는 스트림(FileInputStream)을 생성
  4. BufferedInputStream을 통해 버퍼링: 파일로부터 읽는 스트림을 버퍼링하여 더 효율적으로 데이터를 읽을 수 있도록 구성
  5. @Cleanup을 사용해 자동으로 리소스 해제: @Cleanup 어노테이션으로 inputStream이 더 이상 사용되지 않을 때 자동으로 close() 메서드를 호출하여 스트림을 종료시킴
  6. 파일 데이터 전송: FileCopyUtils.copy(inputStream, response.getOutputStream())을 통해 파일로부터 읽은 데이터를 클라이언트에게 전송하는 HTTP 응답의 출력 스트림(response.getOutputStream())으로 복사

프론트 (Vue.js)

const downloadFile = async (fileOriginNm: string | null, policyFileNm: string | null, policyFlpth: string | null) => {
  if (!fileOriginNm || !policyFileNm || !policyFlpth) return alert('다운로드할 파일 정보가 올바르지 않습니다.')

  const params = {
    fileOriginNm,
    policyFileNm,
    policyFlpth,
  }

  try {
    const queryString = new URLSearchParams(params).toString()
    const response = await instance.get(`/policy/downloadFile?${queryString}`, {
      responseType: 'blob',
    })
    if (!response || !response.data) return alert('데이터가 올바르지 않습니다.')

    const blob = new Blob([response.data])
    const url = URL.createObjectURL(blob)

    const link = document.createElement('a')
    link.href = url
    link.download = fileOriginNm
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)

    URL.revokeObjectURL(url)
  } catch (error) {
    console.error('다운로드 중 오류 발생:', error)
    alert('파일 다운로드 중 오류가 발생했습니다.')
  }
}

ref를 활용할 수 있는 환경이라면 DOM메소드 댜산  ref를 활용해도 괜찮다.

'Java' 카테고리의 다른 글

[Spring Boot] S3 연결하기  (0) 2024.03.29
백엔드 성능 측정  (0) 2024.03.28
[Spring Boot] 에러 핸들링  (1) 2024.02.20
Junit5  (0) 2024.02.17
스프링 부트 서버에 https 설정  (0) 2024.01.23
Comments