SpringBoot+Freemark根据html模板导出PDF
- 1、引入maven
- 2、两个工具类
-
- [2.1 test.html模板](#2.1 test.html模板)
- [2.2 test.html模板中的Freemark语法](#2.2 test.html模板中的Freemark语法)
- 3、controller导出pdf
1、引入maven
导出pdf的一些必要jar包
bash
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>2.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
2、两个工具类
GeneratePDF.java
注意1:工具类中的变量templates 表示在resource建个templates目录, test.html表示生成pdf的模板,water.png表示pdf的水印,这里我没加水印,如果要加水印,只用把下面我注释的三行代码放开就行。
注意2: test.html和water.png都放在templates目录
bash
package cn.yx.zg.utils.pdf;
import cn.hutool.core.io.resource.ClassPathResource;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfPageEvent;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import java.io.*;
import java.nio.charset.Charset;
public class GeneratePDF {
public final static String TEMPLATE_DIRECTORY_INSPECTION = "/templates/";
public final static String TEMPLATE_NAME_INSPECTION = "test.html";
public final static String TEMPLATE_WATER_INSPECTION = "water.png";
/**
* HTML 转 PDF
*
* @param content html内容
* @param outPath 输出pdf路径
* @return 是否创建成功
*/
public static boolean html2Pdf(String content, String outPath) throws FileNotFoundException {
return html2Pdf(content, new FileOutputStream(outPath));
}
public static boolean html2Pdf(String content, OutputStream out) {
try {
Document document = new Document(); //创建一个标准的A4纸文档
PdfWriter writer = PdfWriter.getInstance(document, out);//书写器与ducument文档关联
document.open();//打开文档
// addWaterMark(writer);
writer.setPageEvent(new PdfPageEvent() {
@Override
public void onOpenDocument(PdfWriter pdfWriter, Document document) {
}
@Override
public void onStartPage(PdfWriter pdfWriter, Document document) {
// addWaterMark(pdfWriter);
}
@Override
public void onEndPage(PdfWriter pdfWriter, Document document) {
}
@Override
public void onCloseDocument(PdfWriter pdfWriter, Document document) {
}
@Override
public void onParagraph(PdfWriter pdfWriter, Document document, float v) {
}
@Override
public void onParagraphEnd(PdfWriter pdfWriter, Document document, float v) {
}
@Override
public void onChapter(PdfWriter pdfWriter, Document document, float v, Paragraph paragraph) {
}
@Override
public void onChapterEnd(PdfWriter pdfWriter, Document document, float v) {
}
@Override
public void onSection(PdfWriter pdfWriter, Document document, float v, int i, Paragraph paragraph) {
}
@Override
public void onSectionEnd(PdfWriter pdfWriter, Document document, float v) {
}
@Override
public void onGenericTag(PdfWriter pdfWriter, Document document, Rectangle rectangle, String s) {
}
});
XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"));
document.close();//关闭文档
} catch (Exception e) {
System.out.println("生成模板内容失败" + e.fillInStackTrace());
return false;
}
return true;
}
/**
* HTML 转 PDF
*
* @param content html内容
* @return PDF字节数组
*/
public static byte[] html2Pdf(String content) {
ByteArrayOutputStream outputStream = null;
try {
Document document = new Document();
outputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"));
document.close();
} catch (Exception e) {
System.out.println("------生成pdf失败-------");
}
return outputStream.toByteArray();
}
public static void addWaterMark(PdfWriter writer) {
Image image = null;
try {
ClassPathResource resource = new ClassPathResource(TEMPLATE_DIRECTORY_INSPECTION + TEMPLATE_WATER_INSPECTION);
image = Image.getInstance(resource.getUrl());
// 加入水印
PdfContentByte waterMar = writer.getDirectContentUnder();
// 开始设置水印
waterMar.beginText();
// 设置水印透明度
PdfGState gs = new PdfGState();
// 设置笔触字体不透明度为0.4f
gs.setStrokeOpacity(0.2f);
gs.setFillOpacity(0.2f);
// 设置等比缩放
image.scalePercent(25);// 依照比例缩放
// image.scaleAbsolute(200,100);//自定义大小
image.setRotation(45f);
// 设置透明度
waterMar.setGState(gs);
// 添加水印图片
// waterMar.addImage(image);
image.setAbsolutePosition(110f, 130f);
//结束设置
waterMar.endText();
waterMar.stroke();
try {
waterMar.addImage(image);
} catch (DocumentException e) {
e.printStackTrace();
} finally {
waterMar = null;
gs = null;
}
} catch (BadElementException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
GetHtmlContent.java
bash
package cn.yx.zg.utils.pdf;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
public class GetHtmlContent {
/**
* 获取模板内容
*
* @param templateDirectory 模板文件夹
* @param templateName 模板文件名
* @param paramMap 模板参数
* @return
* @throws Exception
*/
public static String getTemplateContent(String templateDirectory, String templateName, Map<String, Object> paramMap) throws Exception {
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);//不兼容配置
try {
configuration.setTemplateLoader(new ClassTemplateLoader(GetHtmlContent.class, templateDirectory));
// configuration.setDirectoryForTemplateLoading(new File(templateDirectory));//加载模板
} catch (Exception e) {
e.printStackTrace();
}
Writer out = new StringWriter();
Template template = configuration.getTemplate(templateName, "UTF-8");//缓存
template.process(paramMap, out);
out.flush();
out.close();
return out.toString();
}
}
2.1 test.html模板
bash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>测试表单</title>
<style>
body {
font-family: SimSun;
}
.f-s-1 {
font-size: 12px;
}
.table-main {
width: 100%;
border-collapse: collapse;
border-right: 1px solid rgba(0, 0, 0, 0.7);
border-bottom: 1px solid rgba(0, 0, 0, 0.7);
margin-bottom: 30px;
}
.table-main td {
border-left: 1px solid rgba(0, 0, 0, 0.7);
border-top: 1px solid rgba(0, 0, 0, 0.7);
padding: 4px;
}
.th1 {
font-weight: bold;
background-color: #d7d7d7;
}
.th2 {
background-color: #f1f1f1;
}
.text-center{
text-align: center;
}
</style>
</head>
<body>
<h5 style="margin-top: 30px">学生列表</h5>
<table class="table-main f-s-1">
<thead>
<tr>
<td class="th1" style="width: 28%">姓名</td>
<td class="th1 text-center" style="width: 12%">性别</td>
<td class="th1 text-center" style="width: 12%">年龄</td>
<td class="th1 text-center" style="width: 12%">地址</td>
</tr>
</thead>
<tbody>
<#list resultItems as item>
<tr>
<td class="text-center">${item.name}</td>
<td class="text-center">${item.sex}</td>
<td class="text-center">${item.age}</td>
<td class="text-center">${item.address}</td>
</tr>
</#list>
</tbody>
</table>
</body>
</html>
2.2 test.html模板中的Freemark语法
1、 <#list resultItems as item> 表示遍历后台返回的resultItems
2、下面判断age字段是否为空。
bash
<#if age?? >
存在
<#else >
不存在
</#if>
bash
<#--判断数据是否存在,存在则则遍历-->
<#if resultItems??>
<#list resultItems as item>
${item}
</#list>
</#if>
3、controller导出pdf
注意: 代码中设置的变量要和html模板中的变量一致。
bash
package cn.yx.zg.controller;
import cn.yx.zg.utils.pdf.GeneratePDF;
import cn.yx.zg.utils.pdf.GetHtmlContent;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class TestExportPdfController {
@RequestMapping("/test")
public void test(HttpServletResponse response) throws Exception {
Map<String, Object> paramMap = new HashMap<>();
List<Map<String, Object>> resultItems = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Map<String, Object> items = new HashMap<>();
items.put("name", "张三" + i);
items.put("age", "18" + i);
items.put("sex", "男" + i);
items.put("address", "河南" + i);
resultItems.add(items);
}
paramMap.put("resultItems", resultItems);
String destFileName = "测试表单.pdf";
destFileName = new String(destFileName.getBytes(), StandardCharsets.ISO_8859_1);
OutputStream out;
//设置响应
response.setHeader("Content-Disposition", "attachment;filename=" + destFileName);
response.setContentType("application/pdf");
out = response.getOutputStream();
String templateContent = GetHtmlContent.getTemplateContent(GeneratePDF.TEMPLATE_DIRECTORY_INSPECTION, GeneratePDF.TEMPLATE_NAME_INSPECTION, paramMap);
GeneratePDF.html2Pdf(templateContent, out);
out.flush();
}
}