1.自定义Pdf 模板
真实开发场景中,大部分需求都是指定让你在某个地方插入的具体数据是什么,这个时候我们就需要一个PDF 的模板。
(1)新建一个word 文档,编排好你需要的格式。
(2)将编号的文档另存为pdf
(3)使用pdf编辑器,编辑表单,(例如福昕PDF阅读器、Adobe Acrobat DC),在本篇文章中使用的是Acrobat 9 Pro v9.0.0
2.Acrobat 9 Pro v9.0.0的简单使用:
(1)点开软件,打开制作好的pdf 基础模板,点击表单选项,然后点击添加或编辑域。
(2)在表单->表单工具中选择你需要的控件,如果是文本内容一般就使用文本框即可
(3)将控件拖动到指定你想填充数据的地方并拖动鼠标调整大小
(4)双击控件进行一些配置
配置注意项
【1】必须给一个名字,后序在程序中就是通过这个名字找到该文本框并填入内容
【2】给文本框表单域选择隐藏,这样就不会保存之后点开能看到这个框本身
隐藏效果如下:
不隐藏效果如下:
【3】其他细节就自行配置,
(5)配置好之后保存成pdf 即可。
3.Springboot 操作模板添加数据:
1.依赖引入
<!-- PDF操作,itext7全家桶 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.11</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>7.1.11</version>
</dependency>
2.操作模板并返回生成的Pdf
说明:这里我们直接调用接口返回的就是pdf 本身
private void createPDF(HttpServletResponse response, data1) throws IOException {
private static final String DOWNLOAD_PATH = new File(System.getProperty("user.dir")).getParent() + File.separator + "download";
String filePath = DOWNLOAD_PATH + File.separator + "测试.pdf";
PdfWriter writer = new PdfWriter(response.getOutputStream());
//这个template 是在项目的resources 目录下新建的一个template目录,下面存放你的模板
PdfDocument pdfDoc = new PdfDocument(new PdfReader("template/xxx.pdf"), writer);
// 获取页面数量
int totalPages = pdfDoc.getNumberOfPages();
//这里可有可无,这个是自定义字体。
ClassPathResource resource = new ClassPathResource("font/STKAITI.TTF");
PdfFont chineseFont = PdfFontFactory.createFont(toByteArray(resource.getStream()),
PdfEncodings.IDENTITY_H, false);
// 创建 Document 对象
Document document = new Document(pdfDoc, PageSize.A4);
//新增一个方法像模板中添加数据,这里面的数据变量就是你自己的数据
addContentToPdfTemplate(data1, pdfDoc, totalPages, chineseFont, document);
//给pdf 添加水印,水印的字就是mark 变量
addWaterMark(mark, pdfDoc, chineseFont);
pdfDoc.close();
writeBytes(filePath, response.getOutputStream());
}
3.addContentToPdfTemplate方法:
说明:这里面主要是文本类型数据分行插入和图片适应我们配置文本框大小的小实现方式。
private void addContentToPdfTemplate(PdfDataVo dataObj, PdfDocument pdfDoc ,int totalPages, PdfFont chineseFont, Document document) throws IOException {
for (int i = 1; i <= totalPages; i++) {
// 获取页面
PdfPage page = pdfDoc.getPage(i);
// 获取页面的内容
PdfCanvas canvas = new PdfCanvas(page);
List<PdfAnnotation> annotations = page.getAnnotations();
// 遍历页面的注释
for (PdfAnnotation annotation : annotations) {
if (annotation instanceof PdfWidgetAnnotation) {
PdfDictionary dic = annotation.getPdfObject();
PdfName fieldType = dic.getAsName(PdfName.FT);
// 判断是否为需要处理的字段
if (fieldType != null && fieldType.equals(PdfName.Tx)) {
// 获取表单字段的矩形位置信息
Rectangle rect = annotation.getRectangle().toRectangle();
//字体大小,也是在模板中可以配置的选项,我在模板中配置的是14
float fontSize = 14;
// 计算每行容纳的字符数
int charactersPerLine = (int) (rect.getWidth() / fontSize);
// 获取字段的名称
String fieldName = dic.getAsString(PdfName.T).toUnicodeString();
// 根据字段名称设置不同的值
String fieldValue = "";
//从这里的if 开始(content,img等都是我们在模板中给文本框配置的名称)
if ("content".equals(fieldName)) {
String data = removeEmojis(content).replaceAll("…", "...");
fieldValue = data;
String finalValue = fieldValue.length() > 200 ? fieldValue.substring(0, 200) + "..." : fieldValue;
float f = fieldValue.length() > 100 ? 4.5f : 1.2f;
// 分割 content 文本为多行
List<String> lines = splitTextIntoLines(finalValue, charactersPerLine);
// 计算文本所需高度
float lineHeight = fontSize * f; // 可根据实际情况调整行高
float textHeight = lineHeight * lines.size();
// 创建段落对象
Paragraph paragraph = new Paragraph();
paragraph.setFont(chineseFont).setFontSize(fontSize).setTextAlignment(TextAlignment.LEFT).setVerticalAlignment(VerticalAlignment.MIDDLE);
// 添加每行文本到段落中
for (String line : lines) {
paragraph.add(line).add("\n");
}
// 设置段落的位置和宽度
paragraph.setFixedPosition(i, rect.getLeft(), rect.getBottom() + (rect.getHeight() - textHeight) / 2, rect.getWidth());
// 将段落添加到文档中
document.add(paragraph);
} else if ("img".equals(fieldName) && StringUtil.isNotEmpty(dataObj.getSnapshotLink())) {
String imageUrl=dataObj.getSnapshotLink();
if (StringUtil.isNotBlank(imageUrl)) {
//float imageHeight = rect.getWidth(); // 图片的高度
// 加载网络图片并创建图像对象
ImageData imageData = ImageDataFactory.create(imageUrl);
// 获取容器坐标和图片大小
float x = rect.getX();
float y = rect.getY();
float width = imageData.getWidth();
float height = imageData.getHeight();
// 计算缩放比例
float scaleX = rect.getWidth() / width;
float scaleY = rect.getHeight() / height;
float scale = Math.min(scaleX, scaleY);
// 计算缩放后的宽度和高度
float scaledWidth = width * scale;
float scaledHeight = height * scale;
//这个方法的0.0F 参数是源代码中编写的,我们不需要修改就直接搬过来照写
canvas.addImage(imageData,scaledWidth,0.0F,0.0F,scaledHeight,x,y);
}
}
}
}
}
}
}
4.添加水印:
private void addWaterMark(String mark, PdfDocument pdfDoc, PdfFont chineseFont) {
String watermarkText = mark;
Color grayColor = ColorConstants.DARK_GRAY;
float fontSize = 20f;
float opacity = 0.3f; // 设置透明度
for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
PdfPage page = pdfDoc.getPage(i);
PdfCanvas canvas = new PdfCanvas(page);
Rectangle pageSize = page.getPageSize();
float x = pageSize.getWidth();
float y = pageSize.getHeight();
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
// 创建平移变换
AffineTransform transform = AffineTransform.getTranslateInstance(x / 4 * j + 90, y / 4 * k + 50);
//对平移变换进行旋转
transform.rotate(Math.toRadians(50));
canvas.saveState();
PdfExtGState extGState = new PdfExtGState().setFillOpacity(opacity);
canvas.setExtGState(extGState);
canvas.setFillColor(grayColor)
.beginText()
.setFontAndSize(chineseFont, fontSize)
.setTextMatrix(transform)
.showText(watermarkText)
.endText();
canvas.restoreState();
}
}
canvas.release();
}
}
如果该文章对您有点帮助的话,可以麻烦点个赞,谢谢