development

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

big-blog 2020. 3. 1. 15:58
반응형

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


웹 사이트에서 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<InputStreamResource> downloadStuff(@PathVariable int stuffId)
                                                                  throws IOException {
    String fullPath = stuffService.figureOutFileNameFor(stuffId);
    File file = new File(fullPath);

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

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

또한 길이를 계산하기 위해 전체 파일을 읽지 않으려면 이전에 저장하는 것이 좋습니다. 에 대한 문서를 확인하십시오 InputStreamResource.


이 코드는 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);
}

내가 빨리 생각할 수있는 것은 pdf를 생성하고 코드에서 webapp / downloads / <RANDOM-FILENAME> .pdf에 저장하고 HttpServletRequest를 사용 하여이 파일로 전달하는 것입니다.

request.getRequestDispatcher("/downloads/<RANDOM-FILENAME>.pdf").forward(request, response);

뷰 리졸버를 다음과 같이 구성 할 수 있다면

  <bean id="pdfViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
              value="org.springframework.web.servlet.view.JstlView" />
    <property name="order" value=”2″/>
    <property name="prefix" value="/downloads/" />
    <property name="suffix" value=".pdf" />
  </bean>

그리고 그냥 돌아와

return "RANDOM-FILENAME";

아래와 같은 것

@RequestMapping(value = "/download", method = RequestMethod.GET)
public void getFile(HttpServletResponse response) {
    try {
        DefaultResourceLoader loader = new DefaultResourceLoader();
        InputStream is = loader.getResource("classpath:META-INF/resources/Accepted.pdf").getInputStream();
        IOUtils.copy(is, response.getOutputStream());
        response.setHeader("Content-Disposition", "attachment; filename=Accepted.pdf");
        response.flushBuffer();
    } catch (IOException ex) {
        throw new RuntimeException("IOError writing file to output stream");
    }
}

여기에서 PDF를 표시하거나 예제를 다운로드 할 수 있습니다


다음 솔루션이 나를 위해 일합니다.

    @RequestMapping(value="/download")
    public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
        try {

            String fileName="archivo demo.pdf";
            String filePathToBeServed = "C:\\software\\Tomcat 7.0\\tmpFiles\\";
            File fileToDownload = new File(filePathToBeServed+fileName);

            InputStream inputStream = new FileInputStream(fileToDownload);
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment; filename="+fileName); 
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
            inputStream.close();
        } catch (Exception exception){
            System.out.println(exception.getMessage());
        }

    }

누군가에게 도움이된다면. Infeligo가 받아 들인 대답을 제안 할 수 있지만 강제 다운로드를 위해 코드 에이 여분의 비트를 넣으십시오.

response.setContentType("application/force-download");

참고 URL : https://stackoverflow.com/questions/5673260/downloading-a-file-from-spring-controllers



반응형