web-dev-qa-db-ja.com

Spring Controllerからファイルをダウンロードする

WebサイトからPDFをダウンロードする必要があるという要件があります。 PDFはコード内で生成する必要があります。これは、フリーマーカーとiTextのようなPDF生成フレームワークの組み合わせになると思いました。もっと良い方法は?

しかし、私の主な問題は、Spring Controllerを介してユーザーにファイルのダウンロードを許可する方法を教えてください。

336
MilindaD
@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()を持っているとき、あなたはそこに何か書くことができます。この出力ストリームをgenerated PDFをジェネレータに置く場所として渡すことができます。また、送信しているファイルの種類がわかっている場合は、次のように設定できます。

response.setContentType("application/pdf");
360
Infeligo

私はそれをResourceHttpMessageConverterでSpringに組み込まれたサポートを使用することによってこれを流すことができました。 MIMEタイプを決定できる場合、これはcontent-lengthとcontent-typeを設定します。

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

あなたは直接応答にファイルを書くことができるはずです。何かのようなもの

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

その後、ファイルをバイナリストリームとしてresponse.getOutputStream()に書き込みます。最後にresponse.flush()をすることを忘れないでください、そしてそれはそれをするべきです。

75
lobster1234

Spring 3.0ではHttpEntity returnオブジェクトを使うことができます。これを使うなら、あなたのコントローラはHttpServletResponseオブジェクトを必要としないので、テストするのがより簡単です。 これを除いて、この答えはInfeligoのそれに相対的に等しいです

あなたのpdfフレームワークの戻り値がバイト配列(他の戻り値については私の答えの2番目の部分を読んでください):の場合:

@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 Framework(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);
}
72
Ralph

もし、あんたが:

  • 応答に送る前にファイル全体を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 のドキュメントをチェックしてください。

57
acdcjunior

このコードはjsp上のリンクをクリックするとspringコントローラから自動的にファイルをダウンロードするのに問題なく動作しています。

@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();
    }

}
17
Sunil

以下のコードは私がテキストファイルを生成してダウンロードするのに役立ちました。

@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);
}
12
Siva Kumar

私がすぐに考えることができるのは、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";
5
kalyan

以下のようなもの

@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を表示するか、またはダウンロードしてくださいexample ここ

2
xxy

次の解決策は私のために働く

    @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());
        }

    }
1

それが誰にでも役立つなら。あなたはInfeligoによって受け入れられた答えが示唆したことをすることができますが、ただ強制ダウンロードのためにコードにこの余分なビットを入れるだけです。

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