웹 애플리케이션에서 여러 개의 파일을 한 번에 다운로드하도록 제공할 때, 각각의 파일을 별도로 제공하는 대신 하나의 압축된 파일로 묶어서 다운로드를 제공하는 경우가 많습니다. 이를 통해 사용자는 파일 다운로드를 간편하게 할 수 있으며, 네트워크 사용량을 최적화할 수 있습니다. 이번 글에서는 Java를 사용하여 파일들을 압축하고 클라이언트에 다운로드를 제공하는 과정을 상세히 설명합니다.
주요 작업 흐름
- 사용자가 요청한 파일들 확인
- 다운로드하려는 파일 리스트를 서버에서 확인합니다.
- ZIP 파일 생성
- Java의 java.util.zip 패키지를 사용하여 파일들을 ZIP 형식으로 압축합니다.
- HTTP 응답을 통해 압축된 ZIP 파일 제공
- 생성된 ZIP 파일을 HTTP 응답으로 스트리밍하여 사용자에게 다운로드를 제공합니다.
주요 클래스와 메서드
- ZipOutputStream: ZIP 형식의 데이터를 생성하는 데 사용.
- FileInputStream: 파일 데이터를 읽어들이기 위해 사용.
- HttpServletResponse: 생성된 ZIP 파일을 클라이언트에 전달하기 위해 사용.
코드 예제: 파일 압축 후 다운로드
1. 환경 설정
먼저 Java 프로젝트를 설정하고, 필요한 라이브러리를 준비합니다. 아래 코드는 Maven 프로젝트를 기준으로 작성되었습니다.
pom.xml에 의존성 추가 (Spring MVC 사용 시):
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.27</version>
</dependency>
</dependencies>
2. 파일 압축 및 다운로드를 처리하는 코드
아래는 Java와 Spring Boot를 기반으로 파일을 압축하고 다운로드하는 컨트롤러 예제입니다.
Controller 코드
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@RestController
public class FileDownloadController {
private static final String BASE_DIRECTORY = "/path/to/files";
/**
* 여러 파일을 ZIP으로 압축하여 다운로드 제공.
*
* @param fileNames 요청된 파일 이름 리스트
* @param response HttpServletResponse
*/
@GetMapping("/download-zip")
public void downloadZip(
@RequestParam List<String> fileNames,
HttpServletResponse response) {
// 압축 파일의 이름 설정
String zipFileName = "files.zip";
// 응답 설정
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (String fileName : fileNames) {
File file = new File(BASE_DIRECTORY + "/" + fileName);
// 파일이 존재하는지 확인
if (!file.exists()) {
continue;
}
// ZIP에 파일 추가
try (FileInputStream fis = new FileInputStream(file)) {
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
// 파일 내용을 ZIP에 기록
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) >= 0) {
zipOut.write(buffer, 0, length);
}
}
}
zipOut.finish();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 주요 코드 설명
- 파일 경로 지정서버에서 파일이 저장된 디렉토리 경로를 설정합니다.
- private static final String BASE_DIRECTORY = "/path/to/files";
- HTTP 응답 설정다운로드 응답으로 ZIP 파일을 설정합니다. Content-Disposition은 파일 이름을 지정하기 위해 사용됩니다.
- response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName);
- ZIP 파일 생성
- ZipOutputStream을 사용하여 파일을 압축합니다.
- putNextEntry를 호출하여 ZIP 파일에 새 항목을 추가하고, write를 통해 파일 데이터를 기록합니다.
- 예외 처리
- 파일이 존재하지 않는 경우, continue를 사용해 무시.
- 스트림 관련 작업에서 발생하는 예외는 로그를 남겨 문제를 확인.
4. 테스트 요청
이제 http://localhost:8080/download-zip URL로 GET 요청을 보내 파일을 다운로드할 수 있습니다.
예를 들어, 아래와 같은 요청을 통해 특정 파일들을 ZIP으로 묶어 다운로드합니다.
요청 예시:
http://localhost:8080/download-zip?fileNames=file1.txt&fileNames=file2.txt
5. 파일 및 디렉토리 구조
서버 디렉토리 구조는 다음과 같이 준비되어야 합니다:
/path/to/files
├── file1.txt
├── file2.txt
├── image1.jpg
└── document.pdf
6. 개선 사항
- 파일 이름 유효성 검사
- 파일 이름이 유효한지, 악의적인 경로 조작(Path Traversal)이 포함되어 있지 않은지 검증해야 합니다.
if (!fileName.matches("[a-zA-Z0-9._-]+")) { continue; // 유효하지 않은 파일 이름은 스킵 }
- ZIP 파일 크기 제한
- 클라이언트가 너무 많은 파일을 요청하지 않도록 크기 제한을 설정합니다.
if (totalZipSize > MAX_ALLOWED_SIZE) { throw new IllegalArgumentException("Zip file too large!"); }
- 비동기 처리
- 큰 파일이나 많은 파일을 처리할 경우, 비동기 처리를 도입해 서버의 응답 속도를 최적화합니다.
결과 화면
1. 브라우저 동작
사용자가 요청을 보내면 브라우저에서 ZIP 파일이 자동으로 다운로드됩니다. 다운로드된 ZIP 파일에는 요청한 파일들이 포함됩니다.
2. 예외 상황
- 요청한 파일이 없는 경우 ZIP 파일에 포함되지 않습니다.
- 잘못된 요청 형식은 에러로 처리됩니다.
결론
Java를 사용하여 파일을 압축하고 다운로드하는 방법은 생각보다 간단하며, ZipOutputStream 클래스를 활용하면 손쉽게 구현할 수 있습니다. 이번 글에서 제공한 코드를 기반으로 확장 및 최적화를 통해 사용자에게 보다 효율적인 파일 다운로드 기능을 제공할 수 있습니다.
이 방법을 활용하여 여러분의 프로젝트에 파일 다운로드 기능을 구현해 보세요! 😊
'개발 > JAVA' 카테고리의 다른 글
Java에서 여러 타입의 파라미터 받기 (0) | 2025.01.16 |
---|---|
Java에서 Object의 특정타입인지 확인하기 (0) | 2025.01.16 |
특정 웹사이트를 내 웹사이트에 표시하기 (0) | 2025.01.06 |
프로젝트 web.xml 설정을 java로 설정하기 (0) | 2022.02.15 |
Websocket을 이용한 메세지 보내기 받기(java, jsp) (0) | 2020.07.08 |