前言:
一、导入POM包
<!-- freemarker,生成 html -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<!-- 渲染 css 样式 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
<!-- iText,export pdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
二、工具类
package com.ly.backend.common.utils;
import com.itextpdf.text.pdf.BaseFont;
import com.ly.backend.common.constants.FileTemplateConstant;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.stereotype.Component;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* HTML 文件转 PDF 工具
* @author cgy
*/
public class JavaToPdfHtmlFreeMarkerUtil{
private static Configuration freemarkerCfg = null;
static {
freemarkerCfg = new Configuration();
//freemarker的模板目录
try {
freemarkerCfg.setDirectoryForTemplateLoading(new File(FilePathUtil.getCurrentPath()));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void createPdf(String content, String dest, String newFileName) throws IOException, DocumentException {
// step 1
Document document = new Document();
File parentFile = new File(dest);
if (!parentFile.exists()) {
parentFile.mkdirs();
}
System.out.println("-------------->" + dest);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(parentFile.getAbsolutePath() + File.separator + newFileName));
// step 3
document.open();
// step 4
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontImp.register(XinKeConstant.BID_PRICE_HTML_FONT_PATH);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
// step 5
document.close();
}
public static void createPdf2(String content, HttpServletResponse response) throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
// step 3
document.open();
// step 4
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontImp.register(XinKeConstant.BID_PRICE_HTML_FONT_PATH);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
// step 5
document.close();
byte[] pdfBytes = outputStream.toByteArray();
response.setContentLength(pdfBytes.length);
OutputStream os = response.getOutputStream();
os.write(pdfBytes);
os.flush();
os.close();
}
/**
* freemarker渲染html
*/
public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
Writer out = new StringWriter();
try {
// 获取模板,并设置编码方式
Configuration cfg= new Configuration();
Template template = cfg.getTemplate(htmlTmp);
template.setEncoding("UTF-8");
// 合并数据模型与模板
template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
out.flush();
return out.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
/**
* 根据html模版生成PDF文件
*
* @param data
* @param htmlTemplatePath
* @param savePath
* @throws IOException
* @throws DocumentException
*/
public static void convertPdfByHtml(Map<String, Object> data, String htmlTemplatePath, String savePath, String newFileName) throws IOException, DocumentException {
String content = freeMarkerRender(data, htmlTemplatePath);
createPdf(content, savePath, newFileName);
}
// 返回文档流下载
public static void convertPdfByHtml2(Map<String, Object> data, String htmlTemplatePath, HttpServletResponse response) throws IOException, DocumentException {
String content = freeMarkerRender(data, htmlTemplatePath);
createPdf2(content,response);
}
}
三、使用(替换模板)
让前端写好html模板,只能使用原生的标签,然后替换文档里面的参数
// 替换html标签里的参数${parameter!}
// 竖向遍历集合参数
往tr上面添加 <#list companyName as companyName>
结尾 </#list>
// 横向遍历几何参数
往td上加
后端代码:保存在本地
public ResponseDTO downloadReviewConfirmationForm() throws Exception {
// 需要替换的参数
Map<String, Object> data = getReviewConfirmationFormMap();
String fileName = "生成的文件名称";
String template = "模板的路径";
// 设置响应内容类型为PDF
String pdfPath = "保存在本地的地址";
JavaToPdfHtmlFreeMarkerUtil.convertPdfByHtml(data, template, pdfPath, fileName + ".pdf");
return ResponseDTO.success();
}
返回文档流下载
public void downloadBidEvaluationReport(HttpServletResponse response) throws Exception {
// 替换的参数
Map<String, Object> data = downloadBidEvaluationReportMap();
String fileName = "生成的文件名称";
String template = "文档的地址";
// 设置响应内容类型为PDF
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".pdf");
JavaToPdfHtmlFreeMarkerUtil.convertPdfByHtml2(data, template, response);
}