All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.mjyoun.spring.web.service.DownloadService Maven / Gradle / Ivy

package io.github.mjyoun.spring.web.service;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import io.github.mjyoun.core.utils.excel.ExcelUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * Download 기능 관련된 유틸리티 클래스
 * 
 * @author MJ Youn
 * @since 2022. 06. 21.
 */
@Slf4j
@Service(DownloadService.QUALIFIER_NAME)
public class DownloadService {

    public static final String QUALIFIER_NAME = "io.github.mjyoun.spring.web.service.DownloadService";

    private CSVService csvService;

    /**
     * (non-javadoc)
     * 
     * @param csvService
     *            {@link CSVService}
     * 
     * @author MJ Youn
     * @since 2022. 06. 21.
     */
    protected DownloadService(@Qualifier(CSVService.QUALIFIER_NAME) CSVService csvService) {
        this.csvService = csvService;
    }

    /**
     * @see DownloadService#downloadCsv(String, String[], List, char, char, HttpServletResponse)
     * 
     * @param fileName
     *            확장자를 제외한 파일 이름 (확장자는 '.csv' 형태로 자동으로 붙혀줌)
     * @param headers
     *            헤더 목록. null일 경우 헤더가 없는 형태의 csv 파일
     * @param datas
     *            데이터 목록
     * @param response
     *            {@link HttpServletResponse}
     * @throws IOException
     *             FileWriter 닫는중에 오류 발생
     * 
     * @author MJ Youn
     * @since 2022. 06. 21.
     */
    public void downloadCSV(@NotNull String fileName, String[] headers, List datas, HttpServletResponse response) throws IOException {
        this.downloadCsv(fileName, headers, datas, ',', '\0', response);
    }

    /**
     * Array 데이터를 기준으로 CSV 파일로 다운로드해주는 함수
     * 
     * @param fileName
     *            확장자를 제외한, 다운로드할 파일 이름 (확장자는 자동으로 붙혀줌)
     * @param headers
     *            헤더 목록. null일 경우 헤더가 없는 형태의 csv 파일
     * @param datas
     *            데이터 목록
     * @param separator
     *            구분자
     * @param quote
     *            따옴표, 없을 경우 따옴표 하지 않음. 있을 경우 무조건 따옴표로 묶음
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws IOException
     *             FileWriter 닫는중에 오류 발생
     * 
     * @author MJ Youn
     * @since 2022. 06. 21.
     */
    public void downloadCsv(@NotNull String fileName, String[] headers, List datas, char separator, char quote,
            HttpServletResponse response) throws IOException {
        final String methodName = "DownloadService#downloadCSV";

        fileName = new StringBuffer(fileName).append(".csv").toString();
        log.debug("[{}] 다운로드 파일 이름: {}", methodName, fileName);

        // csv content 생성
        byte[] contentBytes = this.csvService.createCSV(fileName, headers, datas, separator, quote);
        InputStream inputStream = new ByteArrayInputStream(contentBytes);

        // download를 위한 disposition 생성
        String contentDisposition = new StringBuffer("attachment; filename=\"") //
                .append(URLEncoder.encode(fileName, "UTF-8").replace("+", "%20")) //
                .append("\"") //
                .toString();

        try {
            response.setContentType(MediaType.TEXT_PLAIN_VALUE);
            response.setContentLength(contentBytes.length);
            response.setHeader("Content-Disposition", contentDisposition);

            FileCopyUtils.copy(inputStream, response.getOutputStream());
            log.debug("[{}] CSV 파일 다운로드 요청 성공 [file name: {}]", methodName, fileName);
        } catch (IOException ioe) {
            log.error("[{}] CSV 파일 다운로드 실패 [msg: {}]", methodName, ioe.getMessage());
            ioe.printStackTrace();
        }
    }

    /**
     * 파일 다운로드
     * 
     * @param filePath
     *            파일 경로. 저장되어 있는 파일 이름으로 다운로드 요청
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws FileNotFoundException
     *             다운로드할 파일에 문제가 있을 경우
     * @throws UnsupportedEncodingException
     *             파일 이름 인코딩 설정이 잘못 되었을 경우. 발생하지 않을 듯..
     * 
     * @author MJ Youn
     * @since 2022. 08. 12.
     */
    public void downloadFile(@NotNull Path filePath, @NotNull HttpServletResponse response)
            throws FileNotFoundException, UnsupportedEncodingException {
        this.downloadFile(filePath.toFile().getName(), filePath, response);
    }

    /**
     * 파일 다운로드
     * 
     * @param downloadFileName
     *            다운로드할 파일의 이름
     * @param filePath
     *            파일 경로
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws FileNotFoundException
     *             다운로드할 파일에 문제가 있을 경우
     * @throws UnsupportedEncodingException
     *             파일 이름 인코딩 설정이 잘못 되었을 경우. 발생하지 않을 듯..
     * 
     * @author MJ Youn
     * @since 2022. 08. 12.
     */
    public void downloadFile(@NotBlank String downloadFileName, @NotNull Path filePath, @NotNull HttpServletResponse response)
            throws FileNotFoundException, UnsupportedEncodingException {
        final String methodName = "DownloadService#downloadFile";

        if (!Files.exists(filePath)) {
            String msg = "존재하지 않는 파일입니다.";
            log.error("[{}] {} [path: {}]", methodName, msg, filePath);
            throw new FileNotFoundException(msg);
        } else if (Files.isDirectory(filePath)) {
            String msg = "디렉토리는 다운로드 할 수 없습니다.";
            log.error("[{}] {} [path: {}]", methodName, msg, filePath);
            throw new FileNotFoundException(msg);
        } else {
            String contentDisposition = new StringBuffer("attachment; filename=\"") //
                    .append(URLEncoder.encode(downloadFileName, "UTF-8").replace("+", "%20")) //
                    .append("\"") //
                    .toString();

            log.debug("[{}] 다운로드 할 파일 이름: {}", methodName, downloadFileName);

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setContentLength((int) filePath.toFile().length());
            response.setHeader("Content-Disposition", contentDisposition);

            try {
                Files.copy(filePath, response.getOutputStream());
                log.debug("[{}] 파일 다운로드 요청 성공 [file name: {}]", methodName, downloadFileName);
            } catch (IOException ioe) {
                log.error("[{}] 파일 다운로드 실패 [msg: {}]", methodName, ioe.getMessage());
                ioe.printStackTrace();
            }
        }
    }

    /**
     * plain text를 파일 형태로 다운로드
     * 
     * @see DownloadService#downloadBytes(String, byte[], HttpServletResponse)
     * 
     * @param downloadFileName
     *            다운로드할 파일 이름
     * @param contents
     *            다운로드할 파일의 내용
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws UnsupportedEncodingException
     *             파일 이름 인코딩 설정이 잘못 되었을 경우. 발생하지 않을 듯...
     * 
     * @author MJ Youn
     * @since 2022. 11. 24.
     */
    public void downloadPlainTextFile(@NotBlank String downloadFileName, @NotNull String contents, @NotNull HttpServletResponse response)
            throws UnsupportedEncodingException {
        byte[] bytes = contents.getBytes();
        this.downloadBytes(downloadFileName, bytes, response);
    }

    /**
     * plain text를 파일 형태로 다운로드
     * 
     * @see DownloadService#downloadPlainTextFile(String, String, HttpServletResponse)
     * 
     * @param downloadFileName
     *            다운로드할 파일 이름
     * @param contents
     *            다운로드할 파일의 목록. `\r\n`로 구분 join함
     * @param response
     *            {@link HttpServletResponse}
     * @throws UnsupportedEncodingException
     *             파일 이름 인코딩 설정이 잘못 되었을 경우
     * 
     * @author MJ Youn
     * @since 2023. 11. 16.
     */
    public void downloadPlainTextFile(@NotBlank String downloadFileName, @NotNull List contents, @NotNull HttpServletResponse response)
            throws UnsupportedEncodingException {
        String _contents = StringUtils.join(contents, "\r\n");
        this.downloadPlainTextFile(downloadFileName, _contents, response);
    }

    /**
     * bytes를 파일 형태로 다운로드
     * 
     * @param downloadFileName
     *            다운로드할 파일 이름
     * @param contents
     *            다운로드할 파일의 내용
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws UnsupportedEncodingException
     *             파일 이름 인코딩 설정이 잘못 되었을 경우. 발생하지 않을 듯...
     */
    public void downloadBytes(@NotBlank String downloadFileName, @NotNull byte[] contents, @NotNull HttpServletResponse response)
            throws UnsupportedEncodingException {
        final String methodName = "DownloadService#downloadBytes";

        String contentDisposition = new StringBuffer("attachment; filename=\"") //
                .append(URLEncoder.encode(downloadFileName, "UTF-8").replace("+", "%20")) //
                .append("\"") //
                .toString();

        log.debug("[{}] 다운로드 할 파일 이름: {}", methodName, downloadFileName);

        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setContentLength((int) contents.length);
        response.setHeader("Content-Disposition", contentDisposition);

        try {
            InputStream inputStream = new ByteArrayInputStream(contents);

            FileCopyUtils.copy(inputStream, response.getOutputStream());
            log.debug("[{}] 파일 다운로드 요청 성공 [file name: {}]", methodName, downloadFileName);
        } catch (IOException ioe) {
            log.error("[{}] 파일 다운로드 실패 [msg: {}]", methodName, ioe.getMessage());
            ioe.printStackTrace();
        }
    }

    /**
     * 엑셀 파일 다운로드
     * 
     * @param fileName
     *            확장자를 제외한, 다운로드할 파일 이름 (확장자는 자동으로 붙혀줌)
     * @param headers
     *            헤더 정보
     * @param datas
     *            데이터 정보
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws IOException
     *             Encoding 에러
     * 
     * @author MJ Youn
     * @since 2024. 02. 07.
     */
    public void downloadExcel(@NotBlank String fileName, @NotNull String[] headers, @NotNull Object[][] datas, HttpServletResponse response)
            throws IOException {
        final String methodName = "DownloadService#downladExcel";

        fileName = new StringBuffer(fileName).append(".xlsx").toString();
        log.debug("[{}] 다운로드 파일 이름: {}", methodName, fileName);

        SXSSFWorkbook workbook = ExcelUtils.create(headers, datas);

        // download를 위한 disposition 생성
        String contentDisposition = new StringBuffer("attachment; filename=\"") //
                .append(URLEncoder.encode(fileName, "UTF-8").replace("+", "%20")) //
                .append("\"") //
                .toString();

        try (OutputStream outputStream = response.getOutputStream()) {
            response.setContentType("text/xlsx");
            response.setHeader("Content-Disposition", contentDisposition);

            workbook.write(outputStream);
            log.debug("[{}] Excel 파일 다운로드 요청 성공 [file name: {}]", methodName, fileName);
        } catch (IOException ioe) {
            log.error("[{}] Excel 파일 다운로드 실패 [msg: {}]", methodName, ioe.getMessage());
            ioe.printStackTrace();
        }
    }

    /**
     * 엑셀 파일 다운로드
     * 
     * @param 
     *            데이터 정보
     * @param fileName
     *            확장자를 제외한, 다운로드할 파일 이름 (확장자는 자동으로 붙혀줌)
     * @param contents
     *            다운로드할 내용
     * @param clazz
     *            파일의 class 정보
     * @param response
     *            {@link HttpServletResponse}
     * 
     * @throws IOException
     *             Encoding 에러
     * 
     * @author MJ Youn
     * @since 2024. 02. 07.
     */
    public  void downloadExcel(@NotBlank String fileName, @NotNull List contents, @NotNull Class clazz, HttpServletResponse response)
            throws IOException {
        final String methodName = "DownloadService#downladExcel";

        fileName = new StringBuffer(fileName).append(".xlsx").toString();
        log.debug("[{}] 다운로드 파일 이름: {}", methodName, fileName);

        SXSSFWorkbook workbook = ExcelUtils.create(contents, clazz);

        // download를 위한 disposition 생성
        String contentDisposition = new StringBuffer("attachment; filename=\"") //
                .append(URLEncoder.encode(fileName, "UTF-8").replace("+", "%20")) //
                .append("\"") //
                .toString();

        try (OutputStream outputStream = response.getOutputStream()) {
            response.setContentType("text/xlsx");
            response.setHeader("Content-Disposition", contentDisposition);

            workbook.write(outputStream);
            log.debug("[{}] Excel 파일 다운로드 요청 성공 [file name: {}]", methodName, fileName);
        } catch (IOException ioe) {
            log.error("[{}] Excel 파일 다운로드 실패 [msg: {}]", methodName, ioe.getMessage());
            ioe.printStackTrace();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy