it-swarm.com.ru

Скачивание файла с пружинных контроллеров

У меня есть требование для загрузки PDF с веб-сайта. PDF необходимо генерировать в коде, который, как я думал, будет представлять собой комбинацию freemarker и инфраструктуры генерации PDF, такой как iText. Есть ли лучший способ?

Тем не менее, моя основная проблема заключается в том, как разрешить пользователю загружать файл через Spring Controller?

337
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(), вы можете написать что угодно. Вы можете передать этот выходной поток как место для помещения сгенерированного PDF в ваш генератор. Кроме того, если вы знаете, какой тип файла вы отправляете, вы можете установить

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

Мне удалось поточить это, используя встроенную поддержку Spring с ResourceHttpMessageConverter. Это установит content-length и content-type, если это может определить mime-тип

@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. Если вы используете это, то вашему контроллеру не нужен объект 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 Framework (documentBbody) уже не является байтовым массивом (а также нет ByteArrayInputStream), он будет было мудро НЕ сделать сначала массив байтов. Вместо этого лучше использовать:

пример с 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 Type и именем отправляемого файла;
  • Пусть другие @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

Этот код прекрасно работает для автоматической загрузки файла с контроллера Spring при нажатии на ссылку на 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();
    }

}
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 или загрузить примеры здесь

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
Jorge Santos Neill

Если это кому-нибудь поможет. Вы можете сделать то, что предложил принятый Infeligo ответ, но просто добавить этот дополнительный бит в код для принудительной загрузки.

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