一、介绍
上一篇文章(java使用freemarker操作word(携带动态表格,图片))https://blog.csdn.net/weixin_45853881/article/details/129298494
紧跟上文,现在不仅需要word,而且还要pdf
二、准备
导入依赖,这里使用iText 5没有使用iText 7的,追求快点写,至于iText 7,下次一定
<!-- iText 5核心库-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.2.0</version>
</dependency>
<!--字体-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
三、实现效果
这里是为了方便查看,就把页码设置在上方了(首页无页码,后续显示页码),下面代码设置的页码就在最下方,所有图片均来源于网络
刚加入了水印设置,懒得截图了也,代码里面有
四、代码
这里把代码都贴上来了,就把一下操作隐藏了,替换为了手敲,先上代码,后展示样式
package com.wy;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.wy.tools.Staff;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class demo {
public static void main(String[] args) throws Exception {
//临时文件目录
String name = "检查报告-" + UUID.randomUUID();
FileOutputStream fos = new FileOutputStream("C:\\Users\\admin\\Downloads\\" + name + ".pdf");
// 服务器对客户端的HTTP请求的响应对象
// HttpServletResponse response
// ServletOutputStream os = response.getOutputStream();
//新建文档
Document document = new Document();
// 将内存中的 PDF 文档内容转换为二进制数据,处理流
PdfWriter writer = PdfWriter.getInstance(document, fos);
writer.setViewerPreferences(PdfWriter.PageModeUseThumbs);
writer.setPageSize(PageSize.A4);
// 注册页码事件
writer.setPageEvent(new PageNumberEvent());
// 注册水印事件
writer.setPageEvent(new WatermarkEvent());
document.open();
// 首页
part1(document,writer);
//内容第一页
document.newPage();
part3(document);
// 查看页码设置生效了没
document.newPage();
Paragraph con = new Paragraph(" ");
document.add(con);
// 关闭文档
document.close();
}
// 首页 封面
public static void part1(Document document, PdfWriter writer) throws Exception{
// pdf首页据上方默认无限边界,所有先设置一个空的 好调整位置,不设置空的也可以,使用时间那里的绝对定位进行设置
// 获取页面尺寸信息(A4默认宽595f,高842f,可根据实际调整)
float pageWidth = document.getPageSize().getWidth();
float pageHeight = document.getPageSize().getHeight();
// 计算居中的坐标(x为页面水平中心)
float centerX = pageWidth / 2;
// 空白占据
Paragraph blank = new Paragraph(" "); //有空格,证明有内容,才可以进行设置间距
blank.setSpacingBefore(10f); // 上方留出10磅的间距
blank.setSpacingAfter(10f); // 下方留出10磅的间距
document.add(blank);
//logo
Paragraph title = new Paragraph();
Image image = Image.getInstance("https://img-home.csdnimg.cn/images/20201124032511.png");
image.scaleToFit(100, 100); // 调整图片大小
title.add(new Chunk(image, 18, 0, true));
Chunk textChunk = new Chunk("CSND", getFont(14, Font.BOLD));
textChunk.setCharacterSpacing(-2f); //字符间距
title.add(textChunk);
title.setIndentationLeft(25f); //左方缩进
document.add(title);
//公司
Paragraph companyName = new Paragraph();
companyName.add(new Chunk("XXX用户", getFont(32,Font.BOLD)));
companyName.add(Chunk.NEWLINE);
companyName.add(new Chunk("文章检测报告", getFont(32,Font.BOLD)));
companyName.setLeading(0, 2.8f);
companyName.setAlignment(Element.ALIGN_CENTER);
companyName.setSpacingBefore(50f); // 上方留出15磅的间距
document.add(companyName);
// 时间
float bottomY = 130f;
ColumnText ct = new ColumnText(writer.getDirectContent());
Paragraph time = new Paragraph();
time.add(new Chunk("官方检测", getFont(18,Font.BOLD)));
time.add(Chunk.NEWLINE);
time.add(new Chunk("二〇二五年七月二十九日", getFont(18,Font.BOLD)));
time.setLeading(0, 1.8f);
time.setAlignment(Element.ALIGN_CENTER);
ct.setSimpleColumn(
centerX - 200f, //左侧
bottomY, //下方
centerX + 200f, //右边
bottomY + 100f //上边
);
ct.addElement(time);
ct.go();
}
//内容页
public static void part3(Document document) throws Exception{
Paragraph title = new Paragraph();
title.add(new Chunk("情况汇总表", getFont(18,Font.BOLD)));
title.setAlignment(Element.ALIGN_CENTER);
title.setSpacingAfter(20f);
document.add(title);
// 创建一个5列的表格
PdfPTable table = new PdfPTable(5);
table.setWidthPercentage(100); // 可以减少宽度以避免边缘挤压,根据实际需要设置
table.setHorizontalAlignment(Element.ALIGN_CENTER); //表格水平居中
// 设置表格列宽比例
float[] columnWidths = {1f, 4f, 3f,4f,3f};
table.setWidths(columnWidths);
// 添加表头
String[] headers = {"序号", "姓名", "年龄","职位","图片"};
for (String header : headers) {
PdfPCell cell = new PdfPCell(new Phrase(header, getFont(12,null)));
cell.setHorizontalAlignment(Element.ALIGN_CENTER); //表头水平居中
cell.setPadding(5);
table.addCell(cell);
}
// 后续替换为接口对接查询
List<Staff> list = new ArrayList<>();
list.add(new Staff("1","张三","30","软件工程师","https://n.sinaimg.cn/sinakd20106/384/w2048h1536/20250517/64b2-bd7d404c74b6c162844f652af698d98e.jpg"));
list.add(new Staff("2","李四","28","产品经理","https://img1.baidu.com/it/u=1520272912,1660814288&fm=253&fmt=auto&app=138&f=JPEG"));
list.add(new Staff("3","王五","26","UI设计师","https://www.vipyl.com/user/webimg/2018123/20181231718374.jpg"));
for (Staff staff : list) {
addDataCell(table, staff.getId(), getFont(12,null));
addDataCell(table, staff.getName(), getFont(12,null));
addDataCell(table, staff.getAge(), getFont(12,null));
addDataCell(table, staff.getWork(), getFont(12,null));
Image image = Image.getInstance(staff.getPic());
image.scaleToFit(100, 100);
PdfPCell imageCell = new PdfPCell(image, true);
imageCell.setHorizontalAlignment(Element.ALIGN_CENTER); // 图片水平居中
imageCell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 图片垂直居中
imageCell.setPadding(5);
table.addCell(imageCell);
}
// 将表格添加到文档
document.add(table);
}
// 添加数据单元格的辅助方法
private static void addDataCell(PdfPTable table, String data, Font font) {
PdfPCell cell = new PdfPCell(new Phrase(data, font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER); // 水平居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
cell.setPadding(5);
table.addCell(cell);
}
// 字体设置
public static Font getFont(Integer size,Integer type) throws Exception {
if (size == null) size = 12;
if (type == null) type = Font.NORMAL;
BaseFont bf = BaseFont.createFont(
"STSong-Light", // 字体名称(宋体)
"UniGB-UCS2-H", // 字符编码(简体中文)
BaseFont.NOT_EMBEDDED // 不嵌入字体(依赖系统字体)
);
Font font = new Font(bf, size, type);
font.setColor(BaseColor.BLACK);
font.setSize(size);
return font;
}
// 页码事件类
public static class PageNumberEvent extends PdfPageEventHelper {
@Override
public void onEndPage(PdfWriter writer, Document document) {
// 跳过首页(页码为1时不显示)
if (writer.getPageNumber() == 1) {
return;
}
PdfContentByte cb = writer.getDirectContent();
try {
// 设置字体,使用支持中文的字体(仍需设置,避免其他内容乱码)
Font font = getFont(10, Font.NORMAL);
// 设置字体到内容字节
cb.setFontAndSize(font.getBaseFont(), font.getSize());
// 计算页码位置(底部居中)
// 从第2页开始,显示实际页码-1(如第2页显示1,第3页显示2)
String pageNumber = String.valueOf(writer.getPageNumber() - 1);
float x = (document.left() + document.right()) / 2;
// float y = document.bottom() - 15; // 设置底部
float y = document.top(); // 设置顶部
// 添加页码
cb.beginText();
cb.setTextMatrix(x, y);
cb.showTextAligned(Element.ALIGN_CENTER, pageNumber, x, y, 0);
cb.endText();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 水印事件类
public static class WatermarkEvent extends PdfPageEventHelper {
@Override
public void onEndPage(PdfWriter writer, Document document) {
// 跳过首页(页码为1时不显示水印)
if (writer.getPageNumber() == 1) {
return;
}
PdfContentByte canvas = writer.getDirectContentUnder();
try {
// 设置水印字体
Font font = getFont(12, Font.BOLD);
// 设置水印文本
String watermarkText = "检测报告";
// 获取页面尺寸
Rectangle pageSize = document.getPageSize();
float width = pageSize.getWidth();
float height = pageSize.getHeight();
// 设置水印颜色和透明度
canvas.saveState();
// 创建 PdfGState 对象并设置透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.5f); // 填充透明度(0-1之间,0完全透明,1完全不透明)
canvas.setGState(gs); // 将透明度应用到画布
canvas.setRGBColorFill(200, 200, 200); // 灰色
canvas.setFontAndSize(font.getBaseFont(), font.getSize());
canvas.setTextMatrix(0, 0);
// 设置水印旋转角度
float angle = 30;
// 计算水印位置并添加多个水印
for (float y = -height / 2; y <= height * 1.5; y += 420) {
for (float x = -width / 2; x <= width * 1.5; x += 300) {
canvas.showTextAlignedKerned(
Element.ALIGN_CENTER,
watermarkText,
x + width / 2,
y + height / 2,
angle
);
}
}
canvas.restoreState();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
实体类,水点字,就不写在同一个类下了
package com.wy.tools;
public class Staff {
private String id;
private String name;
private String age;
private String work;
private String pic;
// 无参构造方法
public Staff() {
}
// 有参构造方法
public Staff(String id, String name, String age, String work, String pic) {
this.id = id;
this.name = name;
this.age = age;
this.work = work;
this.pic = pic;
}
// Getter 和 Setter 方法
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getWork() {
return work;
}
public void setWork(String work) {
this.work = work;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
// 重写 toString 方法
@Override
public String toString() {
return "Study{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
", work='" + work + '\'' +
", pic='" + pic + '\'' +
'}';
}
}