web-dev-qa-db-fra.com

Télécharger un fichier à partir de contrôleurs à ressort

J'ai besoin de télécharger un fichier PDF à partir du site Web. Le PDF doit être généré dans le code, ce qui, à mon avis, serait une combinaison de freemarker et d'un cadre de génération PDF tel que iText. Une meilleure façon?

Cependant, mon principal problème est de savoir comment permettre à l'utilisateur de télécharger un fichier via un contrôleur Spring.

344
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");
    }

}

De manière générale, lorsque vous avez response.getOutputStream(), vous pouvez y écrire n'importe quoi. Vous pouvez transmettre ce flux de sortie en tant qu'emplacement pour mettre PDF généré à votre générateur. De plus, si vous connaissez le type de fichier que vous envoyez, vous pouvez définir

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

J'ai été capable de diffuser cela en utilisant le support intégré de Spring avec ResourceHttpMessageConverter. Ceci définira la longueur du contenu et le type du contenu s'il peut déterminer le 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)); 
}
282
Scott Carlson

Vous devriez pouvoir écrire le fichier directement sur la réponse. Quelque chose comme

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

puis écrivez le fichier sous forme de flux binaire sur response.getOutputStream(). N'oubliez pas de faire response.flush() à la fin et cela devrait le faire.

76
lobster1234

Avec Spring 3.0, vous pouvez utiliser l'objet de retour HttpEntity. Si vous utilisez cela, votre contrôleur n'a pas besoin d'objet HttpServletResponse et il est donc plus facile à tester. Hormis cela, cette réponse est relative égale à celle de Infeligo .

Si la valeur de retour de votre structure pdf est un tableau d'octets (lisez la deuxième partie de ma réponse pour d'autres valeurs de retour) :

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

Si le type de retour de votre PDF Framework (documentBbody) n'est pas déjà un tableau d'octets (et aussi aucun ByteArrayInputStream), il aurait été judicieux PAS pour en faire un tableau d'octets en premier. Au lieu de cela, il vaut mieux utiliser:

exemple avec 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

Si vous:

  • Vous ne voulez pas charger le fichier entier dans un byte[] avant de l'envoyer à la réponse;
  • Vous voulez/devez envoyer/télécharger via InputStream;
  • Vous voulez avoir le plein contrôle du type MIME et du nom du fichier envoyé;
  • Demandez à d’autres @ControllerAdvice de collecter des exceptions pour vous.

Le code ci-dessous est ce dont vous avez besoin:

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

Notez également que pour éviter de lire le fichier entier pour en calculer la longueur, il est préférable de le stocker auparavant. Assurez-vous de vérifier la documentation pour InputStreamResource .

57
acdcjunior

Ce code fonctionne correctement pour télécharger un fichier automatiquement à partir du contrôleur de ressort en cliquant sur un lien sur 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();
    }

}
18
Sunil

Le code ci-dessous m'a permis de générer et de télécharger un fichier texte.

@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

Ce que je peux rapidement penser, c’est générer le fichier PDF et le stocker dans Webapp/downloads/<RANDOM-FILENAME> .pdf à partir du code et envoyer un fichier de transfert à ce fichier à l’aide de HttpServletRequest.

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

ou si vous pouvez configurer votre résolveur de vue quelque chose comme,

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

alors reviens

return "RANDOM-FILENAME";
5
kalyan

quelque chose comme ci-dessous

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

Vous pouvez afficher PDF ou télécharger des exemples ici

2
xxy

La solution suivante fonctionne pour moi

    @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

Si cela aide quelqu'un. Vous pouvez faire ce que la réponse acceptée par Infeligo a suggéré, mais il suffit de mettre ce petit plus dans le code pour un téléchargement forcé.

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