java导入pdf(携带动态表格,图片,纯java不需要模板)

java导出pdf文件

一、介绍

上一篇文章(java使用freemarker操作word(携带动态表格,图片))https://blog.csdn.net/weixin_45853881/article/details/129298494

紧跟上文,现在不仅需要word,而且还要pdf

二、准备

导入依赖,这里使用iText 5没有使用iText 7的,追求快点写,至于iText 7,下次一定

bash 复制代码
<!-- 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>

三、实现效果

所有图片均来源于网络,两个表格使用不同的方法进行写的,水印透明度和颜色可以调节,水印页码也可以调整

刚加入了水印设置,懒得截图了也,代码里面有

四、代码

这里把代码都贴上来了,就把一下操作隐藏了,替换为了手敲,先上代码,后展示样式

bash 复制代码
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 demo1 {
    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);
        // 总览页(表格1)
        document.newPage();
        part2(document);
        //内容第一页(表格2)
        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 logo = new Paragraph();
        Image image = Image.getInstance("https://img-home.csdnimg.cn/images/20201124032511.png");
        image.scaleToFit(100, 100); // 调整图片大小
        logo.add(new Chunk(image, 18, 0, true));
        Chunk textChunk = new Chunk("CSND", getFont(12, Font.BOLD));
        textChunk.setCharacterSpacing(-2f); //字符间距
        logo.add(textChunk);
        blank.setSpacingBefore(2f);
        logo.setIndentationLeft(19f); //左方缩进
        document.add(logo);

        //标题
        Paragraph title = new Paragraph();
        title.add(new Chunk("XXX用户", getFont(28,Font.BOLD)));
        title.add(Chunk.NEWLINE);
        title.add(new Chunk("文章检测报告", getFont(28,Font.BOLD)));
        title.setLeading(0, 2.8f);
        title.setAlignment(Element.ALIGN_CENTER);
        title.setSpacingBefore(49f); // 上方留出49磅的间距
        document.add(title);


        // 底部时间
        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 part2(Document document) throws Exception {
        Paragraph blank = new Paragraph(" ");
        blank.setSpacingAfter(10f);
        document.add(blank);

        Paragraph title = new Paragraph();
        title.add(new Chunk("xxx用户", getFont(18, Font.BOLD)));
        title.add(new Chunk("检测认证", getFont(18, Font.BOLD)));
        title.setAlignment(Element.ALIGN_CENTER);
        title.setSpacingAfter(10f);
        document.add(title);

        Paragraph content = new Paragraph();
        content.add(new Chunk("受xxx委托,xxx官方对xxx用户信息进行审核。",getFont(16, Font.NORMAL)));
        content.setLeading(0, 2.4f); //设置段落的行间距
        // 设置首行缩进(约2个中文字符,假设16号字体下1个字符≈16磅)
        content.setFirstLineIndent(32f);
        content.setSpacingAfter(10f);
        document.add(content);

        // 创建一个2列的表格
        PdfPTable table = new PdfPTable(2);
        table.setWidthPercentage(90); // 可以减少宽度以避免边缘挤压,根据实际需要设置
        // 定义表格各行的单元格内容,按顺序添加
        String[][] cellTexts = {
                {"检查时间:2025.5.29"},
                {"检查渠道:", "CSDN"}, // 第二行第二列将合并到第三行
                {"检查官方:", ""},  // 第三行第二列留空(已被合并)
                {"图片1:",""}, // 合并单元格,使用单元格的值,在进行附加
                {"",""},
        };

        for (int i = 0; i < cellTexts.length; i++) {
            String[] rowTexts = cellTexts[i];
            for (int j = 0; j < rowTexts.length; j++) {
                String cellText = rowTexts[j];
                // 跳过已被合并的单元格 第三行第二列  第四行第二列
                if ((i == 2 || i == 3) && j == 1) {
                    continue;
                }

                PdfPCell cell;
                // 处理需要插入图片的单元格
                if (i == 3  || i == 4) { // 第4行和第5行
                    try {
                        Paragraph paragraph = new Paragraph();
                        Image image;
                        if (i == 3) { //第四行合并了
                            paragraph.add(new Chunk(cellText, getFont(14, Font.NORMAL)));
                            paragraph.add(Chunk.NEWLINE);
                            image = Image.getInstance("https://pics2.baidu.com/feed/e824b899a9014c08c4754f93412bd5037bf4f412.jpeg");
                            image.scaleToFit(100, 100); // 调整图片大小
                            paragraph.add(new Chunk(image, 0, 0, true));
                            cell = new PdfPCell();
                            cell.addElement(paragraph);
                        } else { //第五行有两个
                            if (j == 0) {
                                paragraph.add(new Chunk("图片2:", getFont(14, Font.NORMAL)));
                                paragraph.add(Chunk.NEWLINE);
                                image = Image.getInstance("https://pics2.baidu.com/feed/7e3e6709c93d70cf8e1b7905b58c060bbba12bb5.jpeg");
                                // 设置图片属性
                                image.scaleToFit(100, 100); // 缩放图片以适应单元格
                                cell = new PdfPCell();
                                cell.addElement(paragraph);
                                paragraph.add(new Chunk(image, 0, 0, true));
                            } else {
                                image = Image.getInstance("https://pics6.baidu.com/feed/d833c895d143ad4b000f8b7dce528da4a50f06c2.jpeg");
                                // 设置图片属性
                                image.scaleToFit(100, 100); // 缩放图片以适应单元格
                                image.setAlignment(Image.ALIGN_CENTER); // 图片居中
                                // 创建包含图片的单元格
                                cell = new PdfPCell(image, true); // 第二个参数true表示拉伸图片以填满单元格
                            }
                        }
                    } catch (Exception e) {
                        // 图片加载失败时,使用文本替代
                        cell = new PdfPCell(new Phrase("图片加载失败", getFont(14, Font.ITALIC)));
                        e.printStackTrace();
                    }
                } else {
                    // 普通文本单元格
                    cell = new PdfPCell(new Phrase(cellText, getFont(14, Font.NORMAL)));
                }

                // 第一行合并两列
                if (i == 0) {
                    cell.setColspan(2); // 合并两列
                    cell.setHorizontalAlignment(Element.ALIGN_LEFT); // 左对齐
                }
                // 第二行第二列:合并两行
                if (i == 1 && j == 1) {
                    cell.setRowspan(2); // 合并下面一行
                }
                if (i == 3) {
                    cell.setColspan(2); // 合并两列
                    cell.setHorizontalAlignment(Element.ALIGN_LEFT); // 左对齐
                }

                // 设置单元格内边距
                cell.setPadding(5);
                // 设置单元格内容垂直居中
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);
            }
        }
        // 将表格添加到文档
        document.add(table);
    }

    // 内容页
    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 || writer.getPageNumber() == 2) {
                return;
            }
            PdfContentByte cb = writer.getDirectContent();
            try {
                // 设置字体,使用支持中文的字体(仍需设置,避免其他内容乱码)
                Font font = getFont(10, Font.NORMAL);
                // 设置字体到内容字节
                cb.setFontAndSize(font.getBaseFont(), font.getSize());

                // 计算页码位置(底部居中)
                // 从第3页开始,显示实际页码-2(如第3页显示1,第4页显示2)
                String pageNumber = String.valueOf(writer.getPageNumber() - 2);
                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 = "CSDN检测报告";
                // 获取页面尺寸
                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();
            }
        }
    }

}

实体类,水点字,就不写在同一个类下了

bash 复制代码
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 + '\'' +
                '}';
    }
}
相关推荐
Bruce-li__4 分钟前
Python多线程利器:重入锁(RLock)详解——原理、实战与避坑指南
开发语言·python
懂得节能嘛.8 分钟前
【LangChain4j 详解】Java生态大语言模型框架设计哲学与架构原理
java·人工智能·语言模型
程序员编程指南18 分钟前
Qt 移动应用常见问题与解决方案
c语言·开发语言·c++·qt
许久'22 分钟前
Java面试题
java
33255_40857_2805927 分钟前
使用EasyPOI实现Java订单数据导出(含多物料信息)——模板语法详解与实战
java·excel
kebeiovo32 分钟前
C++代码题部分(1)
开发语言·c++
一个人的幽默37 分钟前
详细聊下easyexcel导出
java
tomato0942 分钟前
河南萌新联赛2025第(二)场:河南农业大学(补题)
开发语言·c++
大山运维1 小时前
好用的在线PDF转图片工具,支持100MB文件
pdf
蓝染yy1 小时前
Spring Boot
java·spring boot