@[TOC]
1 依赖
- 用到的依赖
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.26-incubating</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.4.1</version> </dependency>
2 写freemarker工具类
- freemarker读取模板,替换标签值。
```java
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
/**
- freemarker工具类
* - @Author:胡云峰
@Date:2023/4/14 16:38
*/
public class FreeMarkerUtil {/**
- 获取模板字符串
* - @param templatesPath 模板路径
- @param templateName 模板名称
- @param data 替换数据
@return
*/
public static String getContent(String templatesPath,String templateName,Object data){
// 获取配置
StringWriter writer = new StringWriter();
try {Template template = getConfiguration(templatesPath).getTemplate(templateName); template.process(data,writer);
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
} finally {
writer.flush(); return writer.toString();
}
}/**
- 获取配置
- @param templateFilePath 模板路径
- @return
*/
private static Configuration getConfiguration(String templateFilePath){
// 设置配置信息
Configuration config = new Configuration(Configuration.VERSION_2_3_25);
config.setDefaultEncoding("UTF-8");
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
config.setLogTemplateExceptions(false);
// 获取模板加载器
FileTemplateLoader fileTemplateLoader=null;
try {
} catch (IOException e) {fileTemplateLoader = new FileTemplateLoader(new File(templateFilePath));
}e.printStackTrace();
config.setTemplateLoader(fileTemplateLoader);
return config;
}
- 获取模板字符串
}
# 3 写生成pdf的工具类
* 生成pdf工具
```java
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @Author:胡云峰
* @Date:2023/4/15 9:01
*/
public class PdfUtil {
/**
* 输出内容到pdf
*
* @param outFilePath 输出路径
* @param content 内容
* @param fontPath 字体路径
*/
public static void exportPdfFile(String outFilePath,String content,String fontPath){
// pdf 文件
File file = new File(outFilePath);
// 如果文件所在的父目录不存在,则创建该目录及其所有父目录
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//设置文档大小
Document document = new Document(PageSize.A4);
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
// 创建PdfWriter实例
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
// 设置页眉页脚
MyPdfEvent myPdfEvent = new MyPdfEvent();
myPdfEvent.setFontSize(15);
writer.setPageEvent(myPdfEvent);
// 输出为PDF文件
document.open();
XMLWorkerHelper.getInstance().parseXHtml(writer,document,
new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)),
XMLWorkerHelper.class.getResourceAsStream("/default.css"),
StandardCharsets.UTF_8,
new XMLWorkerFontProvider("E:/siyuan/fonts"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
document.close();
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4 继承PdfPageEventHelper绑定事件
- 设置页眉、页脚
```java
import com.itextpdf.text.;
import com.itextpdf.text.pdf.;
import java.io.IOException;
/**
- 定义页面属性
* - @Author:胡云峰
@Date:2023/4/15 9:48
*/
public class MyPdfEvent extends PdfPageEventHelper {/**
字体文件名称
*/
private String fontFileName;/**
基础字体
*/
private BaseFont baseFont;/**
用于生成中文
*/
private Font font;/**
文档字体大小
*/
private int fontSize;/**
模板
*/
private PdfTemplate templateFoot;/**
页头模板
*/
private PdfTemplate templateHeader;/**
数据实体
*/
private Object data;public MyPdfEvent() {
}/*
关闭每页的时候,写入页眉,页脚等
/
@Override
public void onEndPage(PdfWriter writer, Document document) {
//1.初始化字体
initFront();
//2.写入页眉
writeHeader(writer,document,this.font);
// 3.写入前半部分页脚
try {writeFooter(writer,document,data,this.font);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}/**
@description 初始化字体
*/
private void initFront(){
try {if (this.baseFont == null) { //添加字体,以支持中文
// String fontPath = "E:/siyuan/fonts/华康少女体W5.ttf";
String fontPath = MyPdfEvent.class.getClassLoader().getResource("fonts/ping_fang_light.ttf").getPath(); //创建基础字体 this.baseFont = BaseFont.createFont(fontPath,BaseFont.IDENTITY_H,BaseFont.EMBEDDED); } if (this.font == null) { // 数据体字体 this.font = new Font(this.baseFont, fontSize, Font.NORMAL); }
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}/**
- @param writer PDF编写类
- @param document PDF文档对象
- @param font 字体设置
@description PDF页头设置类
*/
private static void writeHeader(PdfWriter writer, Document document, Font font) {
PdfContentByte cb = writer.getDirectContent();
// 页眉横坐标居中
float x = (document.left() + document.right()) / 2;
// 页眉纵坐标
float y = document.top() + 20;// 绘制页眉 居中
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, new Phrase("我是页眉", font), x, y, 0);// 绘制页眉下划线
cb.setLineWidth(0.5f);
cb.moveTo(document.left(), y-2);
cb.lineTo(document.right(), y-2);
cb.stroke();
}/**
- @param writer PDF编写类
- @param document PDF文档对象
- @param data 业务数据
- @param font 字体设置
@description PDF页脚设置类
*/
public void writeFooter(PdfWriter writer, Document document, Object data, Font font) throws DocumentException, IOException {
// if (data == null) {
// return;
// }
int pageS = writer.getPageNumber();
int currentPage = pageS ;
if (currentPage <= 0) {return;
}
Phrase footer1 = new Phrase( "2023/04/15", font);
Phrase footer2 = new Phrase(currentPage + "/", font);PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, footer1, (document.left() + 10), document.bottom() - 20, 0);
ColumnText.showTextAligned(
cb, Element.ALIGN_RIGHT, footer2, (document.right() - 30), document.bottom() - 20, 0);
//设置模板位置
cb.addTemplate(this.templateFoot, document.right() - 30, document.bottom() - 20);
}@Override
public void onOpenDocument(PdfWriter writer, Document document) {
this.templateFoot = writer.getDirectContent().createTemplate(50,50);
}/*
关闭文档时,替换模板,完成整个页眉页脚组件
/
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
templateFoot.beginText();
templateFoot.setFontAndSize(this.baseFont,this.fontSize);
int total = writer.getPageNumber() - 1;
templateFoot.showText(total+ "");
templateFoot.endText();
templateFoot.closePath();
}public String getFontFileName() {
return fontFileName;
}public void setFontFileName(String fontFileName) {
this.fontFileName = fontFileName;
}public BaseFont getBaseFont() {
return baseFont;
}public void setBaseFont(BaseFont baseFont) {
this.baseFont = baseFont;
}public Font getFont() {
return font;
}public void setFont(Font font) {
this.font = font;
}public int getFontSize() {
return fontSize;
}public void setFontSize(int fontSize) {
this.fontSize = fontSize;
}public PdfTemplate getTemplateFoot() {
return templateFoot;
}public void setTemplateFoot(PdfTemplate templateFoot) {
this.templateFoot = templateFoot;
}public PdfTemplate getTemplateHeader() {
return templateHeader;
}public void setTemplateHeader(PdfTemplate templateHeader) {
this.templateHeader = templateHeader;
}public Object getData() {
return data;
}public void setData(Object data) {
this.data = data;
}
}# 5 测试 ## 5.1 准备数据 * 测试数据 ```java static { // 设置个人信息 person.setName("思源"); person.setAge(1); person.setAvatar("C:\\Users\\Administrator\\Desktop\\siyuan.png"); person.setSex("1"); LocalDate localBirthDate = LocalDate.of(2022, 6, 18); Date birthDate = Date.from(localBirthDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()); person.setBirthDate(birthDate); // 添加宠物 Pet petDog = new Pet("老大","狗"); Pet petCat = new Pet("老二","猫"); Pet petDog2 = new Pet("老三","狗"); Pet petCat2 = new Pet("老四","猫"); List<Pet> pets = Arrays.asList(petDog, petCat,petDog2,petCat2); person.setPetList(pets); }
5.2 测试
- 发送get请求,测试,返回生成pdf路径
@GetMapping("/genePdf") public String generatePdf(){ String temPath = TestController.class.getClassLoader().getResource("templates").getPath(); String content = FreeMarkerUtil.getContent(temPath,"思源.ftl", person); // 定义输出文件路径 String outFile = siYuanConfig.getOutPath() + "/" + "siyuan.pdf"; PdfUtil.exportPdfFile(outFile,content,siYuanConfig.getFontPath()); return outFile; }
5.3 测试结果
- 生成成功
- pdf内容如下:
- 发送get请求,测试,返回生成pdf路径