Загрузка файла из spring контроллеров

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

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

Ответ 1

@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 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");

Ответ 2

Мне удалось передать эту строку, используя встроенную поддержку в 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)); 
}

Ответ 3

Вы должны иметь возможность напрямую записывать файл в ответ. Что-то вроде

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

а затем напишите файл как двоичный поток на response.getOutputStream(). Не забудьте сделать response.flush() в конце, и это должно сделать это.

Ответ 4

С помощью 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-структуры (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);
}

Ответ 5

Если вы:

  • Не нужно загружать весь файл в 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.

Ответ 6

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

}

Ответ 7

Ниже код работал у меня для создания и загрузки текстового файла.

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

Ответ 8

То, что я могу быстро подумать, - создать pdf файл и сохранить его в webapp/downloads/< RANDOM-FILENAME > .pdf из кода и отправить переслать этот файл с помощью HttpServletRequest

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

или если вы можете настроить свой вид resolver как-то вроде

  <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";

Ответ 9

что-то вроде ниже

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

Ответ 10

Следующее решение работает для меня

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

    }

Ответ 11

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

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