[java] 스프링 컨트롤러에서 파일 다운로드

웹 사이트에서 PDF를 다운로드해야하는 요구 사항이 있습니다. PDF는 코드 내에서 생성되어야하는데, 프리 마커와 iText와 같은 PDF 생성 프레임 워크의 조합이라고 생각했습니다. 더 좋은 방법?

그러나 내 주요 문제는 사용자가 Spring Controller를 통해 파일을 다운로드하도록 허용하는 방법입니다.



답변

@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(
    @PathVariable("file_name") String fileName,
    HttpServletResponse response) {
    try {
      // get your file as InputStream
      InputStream is = ...;
      // copy it to response's OutputStream
      org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
      response.flushBuffer();
    } catch (IOException ex) {
      log.info("Error writing file to output stream. Filename was '{}'", fileName, ex);
      throw new RuntimeException("IOError writing file to output stream");
    }

}

일반적으로 말할 때 response.getOutputStream()거기에 무엇이든 쓸 수 있습니다. 생성 된 PDF를 생성기에 넣을 장소로이 출력 스트림을 전달할 수 있습니다. 또한 어떤 파일 형식을 보내고 있는지 알고 있다면 설정할 수 있습니다.

response.setContentType("application/pdf");


답변

Spring의 내장 지원을 ResourceHttpMessageConverter와 함께 사용하여 이것을 스트리밍 할 수있었습니다. MIME 유형을 결정할 수있는 경우 내용 길이와 내용 유형을 설정합니다

@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
    return new FileSystemResource(myService.getFileFor(fileName));
}


답변

응답에 파일을 직접 쓸 수 있어야합니다. 같은 것

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\""); 

파일을에 이진 스트림으로 씁니다 response.getOutputStream(). 이렇게하는 것을 잊지 response.flush()말에 그 그것을해야한다.


답변

Spring 3.0에서는 HttpEntityreturn 객체를 사용할 수 있습니다 . 이것을 사용하면 컨트롤러에 HttpServletResponse객체 가 필요하지 않으므로 테스트하기가 더 쉽습니다.
이 점을 제외하면이 답변은 Infeligo의 답변과 상대적으로 같습니다 .

pdf 프레임 워크의 반환 값이 바이트 배열 인 경우 (다른 반환 값에 대해서는 내 답변의 두 번째 부분을 읽으십시오) :

@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
                 @PathVariable("fileName") String fileName) throws IOException {

    byte[] documentBody = this.pdfFramework.createPdf(filename);

    HttpHeaders header = new HttpHeaders();
    header.setContentType(MediaType.APPLICATION_PDF);
    header.set(HttpHeaders.CONTENT_DISPOSITION,
                   "attachment; filename=" + fileName.replace(" ", "_"));
    header.setContentLength(documentBody.length);

    return new HttpEntity<byte[]>(documentBody, header);
}

당신의 PDF 프레임 워크 (의 반환 형식이있는 경우 documentBbody) 이미 바이트 배열이 아닌 (더도하고 ByteArrayInputStream) 다음은 현명하지 않을 것이다 NOT 먼저 바이트 배열 할 수 있습니다. 대신 다음을 사용하는 것이 좋습니다.

FileSystemResource:

@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
                 @PathVariable("fileName") String fileName) throws IOException {

    File document = this.pdfFramework.createPdf(filename);

    HttpHeaders header = new HttpHeaders();
    header.setContentType(MediaType.APPLICATION_PDF);
    header.set(HttpHeaders.CONTENT_DISPOSITION,
                   "attachment; filename=" + fileName.replace(" ", "_"));
    header.setContentLength(document.length());

    return new HttpEntity<byte[]>(new FileSystemResource(document),
                                  header);
}


답변

만약 너라면:

  • byte[]응답으로 보내기 전에 전체 파일을로드하기를 원하지 않습니다 .
  • 를 통해 전송 / 다운로드를 원하거나 필요로합니다 InputStream.
  • 전송 된 MIME 유형 및 파일 이름을 완전히 제어하고 싶습니다.
  • 다른 @ControllerAdvice픽업 예외가 있거나 없습니다.

아래 코드는 필요한 것입니다.

@RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET)
public ResponseEntity<FileSystemResource> downloadStuff(@PathVariable int stuffId)
                                                                      throws IOException {
    String fullPath = stuffService.figureOutFileNameFor(stuffId);
    File file = new File(fullPath);
    long fileLength = file.length(); // this is ok, but see note below

    HttpHeaders respHeaders = new HttpHeaders();
    respHeaders.setContentType("application/pdf");
    respHeaders.setContentLength(fileLength);
    respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf");

    return new ResponseEntity<FileSystemResource>(
        new FileSystemResource(file), respHeaders, HttpStatus.OK
    );
}

파일 길이 부분에 관해서 : File#length()일반적인 경우에는 충분해야하지만 , 느릴 수 있기 때문에이 관찰을 할 것이라고 생각했습니다. 경우 이전에 저장해야합니다 (예 : DB). 파일이 큰 경우, 특히 파일이 원격 시스템에 있거나 그와 같이 좀 더 정교한 경우 (데이터베이스 등)에는 느릴 수 있습니다.


InputStreamResource

리소스가 파일이 아닌 경우 (예 : DB에서 데이터를 선택하는 경우)를 사용해야합니다 InputStreamResource. 예:

    InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
    return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);


답변

이 코드는 jsp의 링크를 클릭 할 때 스프링 컨트롤러에서 자동으로 파일을 다운로드하는 데 효과적입니다.

@RequestMapping(value="/downloadLogFile")
public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
    try {
        String filePathToBeServed = //complete file name with path;
        File fileToDownload = new File(filePathToBeServed);
        InputStream inputStream = new FileInputStream(fileToDownload);
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition", "attachment; filename="+fileName+".txt");
        IOUtils.copy(inputStream, response.getOutputStream());
        response.flushBuffer();
        inputStream.close();
    } catch (Exception e){
        LOGGER.debug("Request could not be completed at this moment. Please try again.");
        e.printStackTrace();
    }

}


답변

아래 코드는 텍스트 파일을 생성하고 다운로드하는 데 효과적이었습니다.

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> getDownloadData() throws Exception {

    String regData = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
    byte[] output = regData.getBytes();

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("charset", "utf-8");
    responseHeaders.setContentType(MediaType.valueOf("text/html"));
    responseHeaders.setContentLength(output.length);
    responseHeaders.set("Content-disposition", "attachment; filename=filename.txt");

    return new ResponseEntity<byte[]>(output, responseHeaders, HttpStatus.OK);
}