개발/java

서버에 있는 파일 zip으로 다운로드 기능 구현

smile-haha 2024. 5. 31. 22:02
반응형

환경

  • Spring Framework

요구사항

  • 서버에 있는 .min.js와 css와 images 폴더를 zip 파일로 다운로드

프론트

 

1. html 영역

<!--다운로드 버튼-->
<a href="void(0);" onClick="downloadAPI('hahaApi')">hahaApi 다운로드</a>

 

2. javascript 영역

function downloadAPI(apiName){
   // 컨트롤러 경로
   var url = `/apiDownload?apiName=${apiName}`;
   // 새로운 <a> 엘리먼트 생성
   var link = document.createElement("a");
   // 다운로드할 파일의 URL 설정
   link.href = url;
   // 다운로드할 파일의 이름 설정
   link.download = url.substring(url.lastIndexOf("/") + 1);
   // body에 추가
   document.body.appendChild(link);
   // 클릭 이벤트 발생시킴
   link.click();
   // 사용이 끝나면 제거
   document.body.removeChild(link);
}

 

3. java 영역

@Controller
public class DownloadController {

   @RequestMapping(value="/apiDownload", method = RequestMethod.GET)
   @ResponseBody
   public ResponseEntity<Resource> apiDownload(String apiName, Model model) throws IOException {

      String filePath = servletContext.getRealPath("/js/"+apiName+"/");
      String zipFileName = apiName+".zip";

      try{
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try (ZipOutputStream zipOut = new ZipOutputStream(baos)) {
            addFileToZip(filePath, zipOut, apiName+".min.js");
            addFileToZip(filePath, zipOut, apiName+".css");
            addFolderToZip(filePath+"images","images", zipOut);
         }
         byte[] zipBytes = baos.toByteArray();
         ByteArrayResource resource = new ByteArrayResource(baos.toByteArray());

         // 다운로드할 파일명 설정
         HttpHeaders headers = new HttpHeaders();
         headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipFileName);
         headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(zipBytes.length));
         headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);


         // ResponseEntity를 사용하여 HTTP 응답 생성
         return ResponseEntity
               .status(HttpStatus.OK)
               .headers(headers)
               .contentType(MediaType.APPLICATION_OCTET_STREAM)
               .body(resource);

      }catch (IOException ioe) {
         LOGGER.debug("api file write io exception",ioe);
         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
      }
   }

   // 파일을 zip 파일에 추가하는 메서드
   private void addFileToZip(String filePath, ZipOutputStream zipOut, String entryName) throws IOException {
      File file = new File(filePath,entryName);
      if (file.exists() && file.isFile()) {
         try (FileInputStream in = new FileInputStream(file)) {
            zipOut.putNextEntry(new ZipEntry(entryName));
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = in.read(buf)) > 0) {
               zipOut.write(buf, 0, len);
            }
            zipOut.closeEntry();
         }
      }
      else{
         throw new FileNotFoundException("File not found: " + file.getAbsolutePath());
      }
   }

   // 폴더 내 파일을 zip 파일에 추가하는 메서드
   private void addFolderToZip(String folderPath, String folderName, ZipOutputStream zipOut) throws IOException {
      File folder = new File(folderPath);
      if (folder.exists() && folder.isDirectory() && folder.listFiles() != null) {
         for (File file : folder.listFiles()) {
            if (file.isFile()) {
               try(FileInputStream in  = new FileInputStream(file)){
                  zipOut.putNextEntry(new ZipEntry(folderName+"/"+file.getName()));
                  int len = 0;
                  byte[] buf = new byte[4096];
                  while((len = in.read(buf)) > 0) {
                     zipOut.write(buf, 0, len);
                  }
                  zipOut.closeEntry();
               }
            }
            else if (file.isDirectory()){
               String childFolderName = folderName + "/" + file.getName();
               addFolderToZip(file.getAbsolutePath() , childFolderName, zipOut);
            }
         }
      }
      else{
         throw new FileNotFoundException("Folder not found: " + folder.getAbsolutePath());
      }
   }

}

 

반응형