springboot 动态导出pdf
原理是通过freemarker插入数据到html模版里面,html你就叫前端帮你写好,他不写你就告诉你主管让他叫他写,你只管往预留的位置插入数据就行,然后通过itextpdf会将准备好html文件转成PDF。
1、准备依赖
<!--下载pdf begin--><dependency><groupId>com.itextpdf</groupId><artifactId>html2pdf</artifactId><version>4.0.3</version></dependency><!-- freemarker模版 --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.30</version></dependency><!--下载pdf end-->
2、准备html模版
<html><head><metacharset="UTF-8"><style>.main-container{font-family: SF-UI-Text-Regular;width: 21cm;margin: 0 auto;padding: 20px;}.float-left{float: left;}.float-right{float: right;}.padding-left-right{padding-left: 20px;padding-right: 20px;}.margin-left-right{margin-left: 20px;margin-right: 20px;}.section{/*border: 3px dashed #CCC;*//*padding: 20px;*/border-Top: 2px dashed #D3D3D3;padding-Top: 13px;margin-bottom: 16px;margin-Top: 20px;}.section-details p{color: #126089;/*font-size: 16px;*/}.grouper{overflow: hidden;}.grid-50{width: 50%;}@font-face{font-family:'SF-UI-Text-Regular';src:url("https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/fonts/SF-UI-Text-Regular.otf");font-style: normal;}h1{font-size: 22px;font-family:'SF-UI-Text-Regular';}.h1-main{margin-top: 90px;}p{margin: 0 0 10px 0;font-family:'SF-UI-Text-Regular';font-size: 12px;}.p-spec{color: #149a9a;font-weight: bold;}table, th, td{padding: 5px;border-collapse: collapse;}th, td{border: 1px solid #D3D3D3;}.margin-b-30{margin-bottom: 30px;}.row:after{content:"";display: table;clear: both;}.column-4{float: left;width: 33.33%;padding: 10px;}.column-8{float: left;width: 66.66%;padding: 10px;}*{box-sizing: border-box;font-size: 12px;}</style></head><body><divclass="main-container"><divstyle="background-color: #fff"><divclass="grouper main-header grouper padding-left-right"style="padding-top: 20px"><divclass="margin-b-30 row"><divclass="column-4"><imgstyle="max-width:90%"src="https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/Images/WhiteCoat_Tax_Invoice.png"></div><divclass="column-4">
WhiteCoat Holdings Pte Ltd. <br/>
Clinic Licence No.: 18M0119/01/182 <br/>
201 Henderson Road #05-11/12 <br/>
Apex @ Henderson <br/>
Singapore 159545 <br/></div><divclass="column-4">
GST Reg. No: 201610235E <br/>
T: +65 6909 6909 <br/>
F: +65 6909 6909 <br/>
E: [email protected] <br/><astyle="text-decoration: none;"href="https://whitecoat.com.sg/">whitecoat.com.sg</a></div></div></div><divclass="main-body"><divclass="grouper"><divclass="grouper margin-left-right row"style="border-Top: 1px solid #D3D3D3;padding-top:20px;"><divclass="column-4">
Name: <br/>
${data.name!} <br/><br/>
NRIC/FIN/Passport No: <br/>
${data.idNo!}
</div><divclass="column-8">
Invoice No.: <br/>
${data.invoiceNo!} <br/><br/>
Invoice Date: <br/>
${data.invoiceDateStr!} <br/><br/><i>This is a computer generated invoice. No signature is required.</i></div></div><divclass="grouper margin-left-right"style="border-Top: 1px solid #D3D3D3;padding-top:20px;"><table><tr><th>S/N</th><thcolspan="2">Description</th><thstyle="border:1px solid #D3D3D3;">Amount</th></tr><tr><tdstyle="width:30px;text-align:center;">1</td><tdstyle="width:550px;border-right: none">
Medication <br/><#listdata.medicationListasitem>
${item.productName!} <br/></#list><i><br/>Subtotal</i></td><tdstyle="text-align:right;border-left: none">
Quantity <br/><#listdata.medicationListasitem>
${item.quantity!} <br/></#list><istyle="color:#fff"><br/>Subtotal</i></td><tdstyle="width:200px;text-align:right"><br/><#listdata.medicationListasitem>
$${item.amount!} <br/></#list><br/><i>${data.subtotal!}</i></td></tr><tr><tdstyle="text-align:center;">2</td><tdcolspan="2">Administrative charges</td><tdstyle="text-align:right">$${data.adminCharge!}</td></tr><tr><tdcolspan="3"style="text-align:right;border-bottom: none;border-left: none">
Subtotal(Excluding GST)
</td><tdstyle="text-align:right">$${data.subtotalExcludingGST!}</td></tr><tr><tdcolspan="3"style="text-align:right;;border-bottom: none;border-top: none;border-left: none">
GST(${data.tax!}%)
</td><tdstyle="text-align:right">$${data.GST!}</td></tr><tr><tdcolspan="3"style="text-align:right;border-top: none;border-left: none;border-bottom: none">
Total(Including GST)
</td><tdstyle="text-align:right">$${data.totalIncludingGST!}</td></tr></table></div><divclass="grouper margin-left-right float-left"style="padding-bottom:20px;padding-top:20px"><span>
Bank remittance details for payment by Bank Telegraphic <br/>
Transfer in Singapore Dollars to:<br/>
Name of Bank: United Overseas Bank Ltd. Holland Branch<br/>
Account Name: Whitecoat Holdings Pte Ltd.<br/>
Account No: 341-308-316-6<br/>
Bank Code: 7375<br/>
Branch Code: 020<br/>
Bank Swift Code: UOVBSGSG
</span></div></div></div></div></body></html>
3、下载代码
@ApiOperation(value ="下载pdf")@GetMapping("downloadPDF/staffPurchase")publicResponseResultdownload(String id,HttpServletResponse response)throwsException{StaffPurchasePDFVo data = staffPurchaseMapper.getStaffPurchasePDFData(id);HashMap<String,Object> mapData =Maps.newHashMap();
mapData.put("data", data);long timeMillis =System.currentTimeMillis();String templateContent =HtmlUtils.getTemplateContent("Staff_Purchase_Receipt.ftl", mapData);HtmlUtils.html2Pdf(response, templateContent, timeMillis +"");returnResponseResult.success();}
4、htmlutils代码
importcom.itextpdf.html2pdf.ConverterProperties;importcom.itextpdf.html2pdf.HtmlConverter;importcom.itextpdf.layout.font.FontProvider;importfreemarker.template.Configuration;importfreemarker.template.Template;importlombok.extern.slf4j.Slf4j;importorg.springframework.ui.freemarker.FreeMarkerTemplateUtils;importorg.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;importjavax.servlet.ServletOutputStream;importjavax.servlet.http.HttpServletResponse;importjava.io.FileOutputStream;importjava.io.IOException;importjava.net.URISyntaxException;importjava.net.URL;importjava.util.Map;importjava.util.Objects;@Slf4jpublicclassHtmlUtils{/**
* @return
* @throws Exception
*/publicstaticStringgetTemplateDirectory(){ClassLoader classLoader =HtmlUtils.class.getClassLoader();URL resource = classLoader.getResource("templates");try{returnObjects.requireNonNull(resource).toURI().getPath();}catch(URISyntaxException e){
log.error("获取模板文件夹失败,{}", e);}returnnull;}/**
* 获取模板内容
*
* @param templateName 模板文件名
* @param paramMap 模板参数
* @return
* @throws Exception
*/publicstaticStringgetTemplateContent(String templateName,Map<String,Object> paramMap)throwsException{Configuration config =ApplicationContextUtil.getBean(FreeMarkerConfigurer.class).getConfiguration();
config.setDefaultEncoding("UTF-8");Template template = config.getTemplate(templateName,"UTF-8");returnFreeMarkerTemplateUtils.processTemplateIntoString(template, paramMap);}/**
* HTML 转 PDF
*
* @param content html内容
* @param outPath 输出pdf路径
* @return 是否创建成功
*/publicstaticbooleanhtml2Pdf(String content,String outPath){try{ConverterProperties converterProperties =newConverterProperties();
converterProperties.setCharset("UTF-8");FontProvider fontProvider =newFontProvider();
fontProvider.addSystemFonts();
converterProperties.setFontProvider(fontProvider);HtmlConverter.convertToPdf(content,newFileOutputStream(outPath), converterProperties);}catch(Exception e){
log.error("生成模板内容失败,{}", e);returnfalse;}returntrue;}/**
* HTML 转 PDF
*
* @param content html内容
* @return PDF字节数组
*/publicstaticvoidhtml2Pdf(HttpServletResponse response,String content,String filename)throwsIOException{
response.setHeader("Content-Type","application/octet-stream");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition","attachment;filename="+filename+".pdf");try(ServletOutputStream outputStream = response.getOutputStream()){ConverterProperties converterProperties =newConverterProperties();
converterProperties.setCharset("UTF-8");FontProvider fontProvider =newFontProvider();
fontProvider.addSystemFonts();
converterProperties.setFontProvider(fontProvider);HtmlConverter.convertToPdf(content, outputStream, converterProperties);}catch(Exception e){
log.error("生成 PDF 失败,{}", e);}}}
ApplicationContextUtil代码、
importorg.springframework.beans.BeansException;importorg.springframework.boot.autoconfigure.AutoConfigureOrder;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.context.annotation.Configuration;@Configuration@AutoConfigureOrder(-1)publicclassApplicationContextUtilimplementsApplicationContextAware{privatestaticApplicationContext applicationContext =null;publicstaticObjectgetBeanByName(String beanName){if(applicationContext ==null){returnnull;}return applicationContext.getBean(beanName);}publicstatic<T>TgetBean(Class<T> type){return applicationContext.getBean(type);}@OverridepublicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{ApplicationContextUtil.applicationContext = applicationContext;}}
5、freemarker的基本语法
https://developer.aliyun.com/article/942606
6、注意
如果css写了具体的大小比如width: 21cm;,那么下载出来的pdf会因为超出边界被截取,别写。
版权归原作者 Ayu大象 所有, 如有侵权,请联系我们删除。