1.引入依赖
<!--PDF导出POM-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>8.0.3</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>5.0.3</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
2.编写FTL文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<style>
.pic {
width: 100%;
height: 100%;
}
</style>
<body>
<div id="app">
<#--封面图-->
<#if show>
<img class="pic" src="${coverImageFile!''}"/>
</#if>
</div>
</body>
</html>
3.后台代码
@Resource
Configuration configuration;
/**
* 导出
*/
@Override
public void export(HttpServletResponse response){
//获取文件byte[]
byte[] pdfBytes=getPdfBytes();
try{
//输出pdf文件
String chineseName="中文文件名";
response.setCharacterEncoding("utf-8");
String fileName=URLEncoder.encode(chineseName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".pdf");
//设置响应头(导出为pdf文件)
response.setContentType("application/pdf");
//设置响应头(返回流给前端预览使用)
//response.setContentType("application/octet-stream;charset=UTF-8");
// 获取HttpServletResponse的OutputStream
OutputStream os=response.getOutputStream();
// 写入字节流数组
os.write(pdfBytes);
os.flush();
os.close();
}catch(IOException e){
throw new InvalidCmdException(e.getMessage());
}
}
private byte[] getPdfBytes(){
//获取模板替换数据
Map<String, Object> map=new HashMap<>();
map.put("show", true);
map.put("coverImageFile", "base64图片");
try{
//读取freemarker模板
Template template=configuration.getTemplate("FTL文件路径");
StringWriter out=new StringWriter();
// 将数据模型合并到模板中生成HTML
template.process(map, out);
String htmlContent=out.toString();
// 初始化字节输出流用于保存PDF
ByteArrayOutputStream pdfOutput=new ByteArrayOutputStream();
// 设置中文字体
ConverterProperties converterProperties=new ConverterProperties();
FontProvider fontProvider=new DefaultFontProvider(true, true, false);
PdfDocument pdfDoc;
FontProgram fontProgram=FontProgramFactory.createFont("static/simhei.ttf");
// 添加中文字体到字体提供者
fontProvider.addFont(fontProgram);
converterProperties.setFontProvider(fontProvider);
// 转换HTML到PDF
try(ByteArrayOutputStream outputStream=pdfOutput){
// 初始化文档
PdfWriter writer=new PdfWriter(outputStream);
pdfDoc=new PdfDocument(writer);
//设置pdf纸张大小
pdfDoc.setDefaultPageSize(PageSize.A4);
// 将HTML转换为PDF
HtmlConverter.convertToPdf(htmlContent, pdfDoc, converterProperties);
}
// 从字节输出流中获取PDF的字节数组
byte[] pdfBytes=pdfOutput.toByteArray();
// 关闭流
pdfOutput.close();
pdfDoc.close();
out.close();
return pdfBytes;
}catch(IOException e){
throw new InvalidCmdException("读取候选人freemarker模板错误");
}catch(TemplateException e){
throw new InvalidCmdException("替换模板值错误");
}
}
4.注意事项
itext7本身不支持中文 所以需要在项目中引入字体文件。
freemarker图片需要使用base64格式图片
byte[] 数组转base64
/**
* 图片转base64
*/
private String convertBase64(String ossFileId){
if(String2Utils.isNotBlank(ossFileId)){
//这里使用的是阿里的oss查询
OssUrlDto ossUrlDto=ossFileService.findDfsById(ossFileId).orElse(null);
try{
byte[] adviserBytes=ossClientService.getContentByteByKey(ossUrlDto.getBucketName(), ossUrlDto.getPath());
return "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(adviserBytes);
}catch(Exception e){
throw new InvalidCmdException("图片转base64失败");
}
}
return "";
}
给导出的PDF设置页面边距,网上搜索了很多中办法,只有一种成功了
再FTL页面中添加
<style>
@page {
size: A4;
margin: 10mm;
}
</style>