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.
@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");
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));
}
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.
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:
InputStreamResource
,PathResource
(depuis le printemps 4.0) ouFileSystemResource
,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);
}
Si vous:
byte[]
avant de l'envoyer à la réponse;InputStream
;@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
.
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();
}
}
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);
}
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";
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
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());
}
}
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");