在實(shí)際應(yīng)用中有這么一個(gè)場景,用戶希望在頁面上有一個(gè)下載按鈕,點(diǎn)擊按鈕時(shí)把當(dāng)前頁的內(nèi)容生產(chǎn)一個(gè)PDF文件下載下來。
這個(gè)需求有兩種表現(xiàn)形式,一種是當(dāng)用戶點(diǎn)擊按鈕時(shí)直接在瀏覽器中彈出保存框下載PDF文件,另一種是返回PDF的視圖,在瀏覽器中預(yù)覽PDF文件的內(nèi)容,然后再下載。
這里分別介紹兩種實(shí)現(xiàn)方式:
一、直接下載PDF文件
本質(zhì)上來說,把PDF文件讀取到inputStream中,繼而放入返回的的實(shí)體中。
返回的ResponseEntity中,注意指定Content-Type的內(nèi)容為application/pdf,
且Content-Disposition的內(nèi)容為attachment; filename="helloWorld.pdf"
@RequestMapping(value = "/pdfDownload", method = GET)
public ResponseEntity download() throws IOException {
File file = new File("HelloWorld.pdf");
InputStream in = new FileInputStream(file);
final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/pdf");
headers.add("Content-Disposition", "attachment; filename=" + file.getName() );
return new ResponseEntity<>(IOUtils.toByteArray(in), headers, HttpStatus.OK);
}
該方法在瀏覽器中直接訪問localhost:8080/pdfDownload就回彈出一個(gè)文件保存框,選擇保存的本地路徑即可下載,或者有的效果是直接在瀏覽器中下載了PDF文件,這是因?yàn)樗褂玫臑g覽器本身的下載設(shè)置,可以根據(jù)個(gè)人喜好來設(shè)置究竟彈出還是不彈出保存框。
二、瀏覽器預(yù)覽PDF文件,再下載
如果使用的不是RestController,就可以直接返回一個(gè)String字符串,內(nèi)容為PDF文件的視圖名稱,這里定義為helloWorldPDF,該視圖名在views.properties中配置
@RequestMapping(value = "/pdfDownload2", method = GET)
public String download2(HttpServletRequest request) throws IOException {
return "helloWorldPDF";
}
resource資源文件夾中的views.properties文件的內(nèi)容為:
helloWorldPDF.(class)=com.test.report.PDFView
這里的com.test.report.PDFView指的是定義的PDF視圖的內(nèi)容。
我們使用了itextpdf的jar包來生成PDF文件的內(nèi)容。
compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.6'
public class PDFView extends AbstractView {
public PDFView() {
setContentType("application/pdf");
}
@Override
protected boolean generatesDownloadContent() {
return true;
}
@Override
protected final void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ByteArrayOutputStream baos = createTemporaryOutputStream();
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, baos);
writer.setViewerPreferences(PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage);
document.open();
Paragraph header = new Paragraph(new Chunk("hello world"));
document.add(header);
document.close();
writeToResponse(response, baos);
}
}
以上就生成了我們需要的PDF文件的內(nèi)容,并放進(jìn)ByteArrayOutputStream中,調(diào)用writeToResponse方法把字節(jié)流傳進(jìn)response中。
因?yàn)槭褂玫氖荢pringBootApplication,所以需要加的一些配置是在 Application 的包含main方法的class中進(jìn)行的
@Bean
public ResourceBundleViewResolver viewResolver() {
ResourceBundleViewResolver resolver = new ResourceBundleViewResolver();
resolver.setOrder(1);
resolver.setBasename("views");
return resolver;
}
如此一來就可以直接在瀏覽器中訪問localhost:8080/pdfDownload2看到PDF文件的預(yù)覽頁面,在頁面中可以進(jìn)行下載,打印等操作。