JAVA开发 PDF文件生成表格,表格根据内容自动调整高度

1、展示效果

在这里插入图片描述
在这里插入图片描述

2、相关功能实现

JAVA开发 使用Apache PDFBox库生成PDF文件,绘制表格

3、实现代码

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import java.io.File;
import java.io.IOException;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TableInPDFBox {

     private static final int WARPNUM  = 11;   //每行显示的字符数量,一个中文占一个字符,其他字符占0.5个

    //判断输入的字符是不是中文
    public static boolean isChineseChar(char ch) {
        String regex = "[\u4E00-\u9FA5]";
        String charToCheck = String.valueOf(ch);
        return charToCheck.matches(regex);
    }

    //每行显示的字符数量,获取每个字符串所需要的行数
    public static  int GetWarpRowByString(String str){
        float sum = 0 ;   //sum 用来计算中文字符
        int row = 0,index=0;
        char[] tempArr = str.toCharArray();
        for(int i = 0;i<tempArr.length;i++){
            if(isChineseChar(tempArr[i])){
                sum +=1;
            }else{
                sum +=0.5f;
            }
            if(sum == WARPNUM){
                row++;
                sum=0;
            }else if(sum>WARPNUM){
                i--;
                row++;
                sum = 0;
            }else{

            }
        }
        row = row +1;
        return row;
    }

    //根据每行的内容,获取最大需要换行的行数(只比较爱好、优势两列)
    public static int[] ConfirmRowLength(String[][] stu,int index){
        int[] MaxlengthArr = new int[stu.length];
        MaxlengthArr[0] = 1;
        for(int i = 1;i<stu.length;i++){
            int max = GetWarpRowByString(stu[i][0]);
            for(int j=index;j<stu[i].length;j++){
                int strRow = GetWarpRowByString(stu[i][j]);
                if(strRow>max){
                    max = strRow;
                }
            }
            MaxlengthArr[i] = max;
        }
        return MaxlengthArr;
    }

    //将字符串按照最大每行显示数进行分割,保存到字符串数组中
    public static String[] GetWarpStr(int rowLength,String str){
        float sum = 0.0f;
        String[] returnStr=new String[rowLength];
        int returnIndex = 0;
        String temp="";
        char[] strArr = str.toCharArray();
        for(int i= 0;i<strArr.length;i++){
            if(isChineseChar(strArr[i])){
                sum = sum + 1.0f;
            }else{
                sum+=0.5f;
            }
            temp = temp + strArr[i];
            if(sum == WARPNUM){
                returnStr[returnIndex++]= temp;
                temp = "";
                sum = 0.0f;
            }else if(sum >= WARPNUM){
                returnStr[returnIndex++]= temp.substring(0,temp.length()-1);
                i--;
                temp = "";
                sum = 0.0f;
            }else{

            }
        }
        if(!temp.isEmpty() && returnIndex<rowLength){
            returnStr[returnIndex++] = temp;
        }
        return returnStr;
    }


    public static void main(String[] args) {
        PDDocument document = null;
        String[][] stuData = new String[][]{{"姓名","工号","部门","爱好","优势"}
                ,{"张三丰","WD0001","武当派","阅读让我们获得知识和灵感,运动可以让我们保持身体健康。阅读让我们获得知识和灵感,运动可以让我们保持身体健康。阅读让我们获得知识和灵感,运动可以让我们保持身体健康。阅读让我们获得知识和灵感,运动可以让我们保持身体健康。","武当派和三丰派的祖师,会少林武功和九阳真经,武功特点是阴阳互融、刚柔并济,达到了武学的巅峰。真是泰裤辣。武功特点是阴阳互融、刚柔并济,达到了武学的巅峰。真是泰裤辣"}
                ,{"郭  襄","EM0001","峨嵋派","书法有助于修养身心,陶冶情操,既练习了字,也可以修炼沉稳的性格.书法有助于修养身心,陶冶情操,既练习了字,也可以修炼沉稳的性格。","会峨眉九阳功,擅长黄药师最精妙的剑法之一的落英剑法。"}};
        try {
            int[] lengthArr = ConfirmRowLength(stuData,3);
            float[] rowIndxArr = new float[stuData.length+1];
            float[] colIndxArr = new float[stuData[0].length+1];
            document = new PDDocument();
            PDPage page = new PDPage();
            document.addPage(page);

            PDPageContentStream contentStream = new PDPageContentStream(document, page);

            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss");
            String dateFormat = sdf.format(date);

            // 表格参数
            int rows = 3;
            int cols = 5;
            float cellWidth1 = 60 , cellWidth2 = 150;
            float cellHeight = 30;
            float xStart = 30,xEnd = xStart + 3 * cellWidth1+2*cellWidth2;       //横向开始线的x点,横向结束线的x点
            float yStart = 700,yEnd = 0;   //纵向开始线的y点,纵向结束线的y点


            float sumRows = cellHeight;
            // 绘制表格x轴线
            for (int i = 0; i <= rows; i++) {
                float rowY =0;
                if(i == 0){
                    rowY = yStart - i * cellHeight;
                }else{
                    sumRows =  sumRows +lengthArr[i-1]*10+5*2;
                    rowY = yStart - sumRows;
                    yEnd = rowY;
                }
                rowIndxArr[i] = rowY;
                contentStream.moveTo(xStart, rowY);
                contentStream.lineTo(xEnd, rowY);
                contentStream.stroke();
            }

            //绘制表格y轴线
            for (int j = 0; j <= cols; j++) {
                float colX;
                if(j<=3){
                    colX= xStart + j * cellWidth1;
                }else{
                    colX = xStart +3*cellWidth1 +(j-3)*cellWidth2;
                }
                colIndxArr[j] = colX;
                contentStream.moveTo(colX, yStart);
                contentStream.lineTo(colX, yEnd);
                contentStream.stroke();
            }

            // 填写表格内容
            File fontFile = new File("C:\\Windows\\Fonts\\SIMLI.TTF"); // 字体文件路径
            PDType0Font font = PDType0Font.load(document, fontFile);
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    String text = stuData[i][j];
                    String[] rowText = GetWarpStr(lengthArr[i],text);
                    for(int k = 0;k<rowText.length && rowText[k]!=null;k++){
                        contentStream.beginText();
                        contentStream.setFont(font, 12);
                        contentStream.newLineAtOffset(colIndxArr[j]+5, rowIndxArr[i]-10-10*k);
                        contentStream.showText(rowText[k]);
                        contentStream.endText();
                    }
                }
            }

            contentStream.close(); // 关闭内容流

            // 保存PDF
            document.save("D:\\JAVAFILE\\attachments\\pdfs\\" + dateFormat + "  table.pdf");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                try {
                    document.close(); // 关闭文档
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/700138.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

龙芯+RT-Thread+LVGL实战笔记(36)——密码锁完善

【写在前面】不知不觉中,又临近学期末了。这个学期,因为一些特殊原因,一直没怎么更新本教程,而且不得已上调了本教程的价格,在此笔者深表歉意。另一方面,自己带的学生发挥不佳,很遗憾未能闯进国赛,为此笔者也郁闷了相当长一段时间。事已至此,也只能慢慢释然,来年再战…

Python实现音乐播放器 -----------内附源码

Python做一个简易的音乐播放器 简易音乐播放器 import time import pygamefile r歌曲路径 pygame.mixer.init() print(正在播放,file) track pygame.mixer.music.load(file) pygame.mixer.music.play() time.sleep(130) pygame.mixer.music.stop()运行效果&#xff1a; 开始…

计算机网络:网络层 - IPv4地址

计算机网络&#xff1a;网络层 - IPv4地址 分类编址划分子网子网掩码 无分类编址 CIDRCIDR 地址块构造超网 在酒店中&#xff0c;每个房间都有门牌号码&#xff0c;服务员送餐时&#xff0c;就可以根据门牌号码来判断一份餐要送到那个房间。 在网络中也是如此&#xff0c;一份…

万万没想到,一个不起眼的小功能,差点把我们项目搞崩溃!

大家好&#xff0c;我是程序员鱼皮。今天分享一个真实项目开发的小故事。 故事 最近我们团队一直在持续更新编程导航网站&#xff0c;优化了界面&#xff0c;也新增了不少功能。现在网站长下面这样&#xff0c;是不是看着比以前舒服多了&#xff1f; 编程导航&#xff1a;htt…

2024泰迪智能科技大数据实训室方案

大数据实训室的主要目的是培养大数据平台运维项目的实践能力,以数据计算、分析、挖掘和可视化的案例训练为辅助。实训室旨在培养德智体全面发展、遵纪守法、掌握大数据平台运维基本技能、具备大数据应用、分析和系统管理与运维能力的高素质大数据技术人才。 大数据实训室建设的…

理解科研中的空间域和时域和频域

文章目录 空间域时域频域频域中的高低概念 读了很多的论文后&#xff0c;才感知到论文中常说的什么空间域怎么怎么样&#xff0c;时域怎么怎么样&#xff0c;频域怎么怎么样。 本文其实主要写的是频域。 空间域 spatial domain &#xff1b; 时域 temporal domain &#xff1b…

【Modelground】个人AI产品MVP迭代平台(4)——Mediapipe视频处理网站介绍

文章目录 介绍模型配置输入输出核心实现&#xff08;源码&#xff09;总结 介绍 这篇文章我将硬核介绍Modelground的第一个产品——Mediapipe视频处理&#xff01;网站入口为https://tryiscool.space/ml-video/&#xff0c;如图所示&#xff0c;欢迎体验。 tip: 由于服务器带宽…

Query传递的参数需不需要加注解?加什么?为什么有的时候要加有的时候不加?

Query传递过来的参数可以加&#xff0c;也可以不加注解。如果要加&#xff0c;是在传递的参数名和后端的变量名不一致的情况下&#xff0c;要加RequestParam如果传递过来的参数名和后端的变量名一致&#xff0c;则可以不加RequestParam。 传递过来的数据如果是通过 Query 方式…

Java操作数据库 —— JDBC ① 基础篇

我走我的路&#xff0c;有人拦也走&#xff0c;没人陪也走 —— 24.6.7 JDBC JDBC就是使用Java语言操作关系型数据库的一套API 一、JDBC简介 JDBC 概念 JDBC 就是使用Java语言操作关系型数据库的一套API 全称:(Java DataBase Connectivity)意为Java 数据库连接 JDBC 本质: ①…

7种常用数据分析方法,建议收藏学习(下)

在上一篇内容里&#xff0c;我们提到了常用的数据分析放法&#xff0c;比如&#xff1a;漏斗分析法、留存分析法、分组分析法、矩阵分析法。没有看到的上篇推送的小伙伴可以回过头去查看我们之前的推送。 今天&#xff0c;我们继续讲后面的内容&#xff1a;关联分析法、指标分…

图钉AI导航

1、图钉AI导航 https://www.tudingai.com/

MySQL复习题(期末考试)

MySQL复习题&#xff08;期末考试&#xff09; 1.MySQL支持的日期类型&#xff1f; DATE,DATETIME,TIMESTAMP,TIME,TEAR 2.为表添加列的语法&#xff1f; alter table 表名 add column 列名 数据类型; 3.修改表数据类型的语法是&#xff1f; alter table 表名 modify 列名 新…

【机器学习】让计算机变得更加智能

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 目录 机器学习&#xff1a;让计算机…

springmvc 全局异常处理器配置的三种方式深入底层源码分析原理

文章目录 springmvc 全局异常处理器配置的三种方式&深入底层源码分析原理配置全局异常处理器的三种方式实现接口HandlerExceptionResolver并配置到WebMvcConfigurer注解式配置ExceptionHandlercontroller里方法上定义ExceptionHandler 深入源码分析进入DispatcherServlet执…

Jmeter07:函数

1 Jmeter组件&#xff1a;函数 1.1 是什么&#xff1f; 是程序中的封装单元&#xff08;最小的&#xff09;&#xff0c;封装一些功能实现 1.2 为什么&#xff1f; 优点1&#xff1a;易读 易维护 优点2&#xff1a;实现功能复用 1.3 怎么用&#xff1f; 流程&#xff1a; 1&…

HCIE认证,这些误区要避开

追求HCIE认证是许多网络工程师提升职业水平的选择之一。 然而&#xff0c;在这条备考之路上&#xff0c;存在不少误解可能会误导你的学习方向或影响你的备考效率。 了解并避开这些常见误区&#xff0c;将帮助你更有效地准备HCIE认证考试。 01 误区一&#xff1a;过分依赖题库 …

【Three.js】知识梳理二:Three.js引用和环境搭建

1.文件包下载和目录简介 1.1 文件包下载 a. 官方网站下载&#xff1a; 访问 Three.js 的官方网站&#xff08;threejs.org/&#xff09;并点击 "Download" 按钮&#xff0c;下载最新版本的文件包。 b. GitHub仓库下载&#xff1a; 访问 Three.js 的 GitHub 仓库&a…

面向对象设计原则概述

面向对象设计原则概述 面向对象设计原则概述 面向对象设计原则概述单一职责原则开闭原则里氏代换原则依赖倒转原则接口隔离原则合成复用原则迪米特法则 内容来自《设计模式与艺术》一文。后续会陆续分享书中值得深思观点。 面向对象设计的目标之一在于支持可维护性复用&#xf…

Django UpdateView视图

UpdateView是Django中的一个通用视图&#xff0c;用于处理对象的更新操作。它允许用户更新一个已经存在的对象。UpdateView通常与一个模型表单一起使用&#xff0c;这样用户就可以看到当前对象的值&#xff0c;并可以修改它们。 1&#xff0c;添加视图 Test/app3/views.py fr…

第十九节:暴力递归到动态规划

一 动画规划的概念 优化出现重复解的递归 一旦写出递归来&#xff0c;改动态规划就很快 尝试策略和状态转移方程是一码事 学会尝试是攻克动态规划最本质的能力 如果你发现你有重复调用的过程&#xff0c;动态规划在算过一次之后把答案记下来&#xff0c;下回在越到重复调用过程…