java - pdfbox生成pdf文件(制表格)

news/2025/11/27 11:53:06/文章来源:https://www.cnblogs.com/xzyyds233/p/19276815

因为调不来合并单元格的展示形式,所以暂时不用了。其它部分可以直接使用,想修改的话需要读懂怎么拼接的。有类似生成表格的需求可以试试itext

直接调这个方法generatePdf传参数就可以了 。其实是求dk写的,但是调不明白,丢了感觉浪费,说不定会发挥点什么作用,万一有人用到呢

 

 

  1     public byte[] generatePdf(List<Map<String, String>> dataList, String instrumentName) {
  2         try (PDDocument document = new PDDocument();
  3              ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
  4             
  5             // 计算总页数
  6             int totalPages = (int) Math.ceil((double) dataList.size() / 10);
  7             if (totalPages == 0) totalPages = 1; // 至少一页
  8             PDFont chineseFont = PDType0Font.load(document, new File("C:/Windows/Fonts/simhei.ttf"));
  9             // 分页处理数据
 10             for (int pageNum = 0; pageNum < totalPages; pageNum++) {
 11                 // 计算当前页的数据范围
 12                 int startIndex = pageNum * 10;
 13                 int endIndex = Math.min(startIndex + 10, dataList.size());
 14                 List<Map<String, String>> pageData = dataList.subList(startIndex, endIndex);
 15                 
 16                 // 创建新页面
 17                 PDPage page = new PDPage(PDRectangle.A4);
 18                 document.addPage(page);
 19                 
 20                 PDPageContentStream contentStream = new PDPageContentStream(document, page);
 21                 
 22                 try {
 23                     // 绘制当前页的表格
 24                     drawTableForPage(contentStream, pageData, instrumentName, pageNum + 1, totalPages, startIndex,chineseFont);
 25                 } finally {
 26                     contentStream.close();
 27                 }
 28             }
 29             
 30             document.save(baos);
 31             return baos.toByteArray();
 32             
 33         } catch (Exception e) {
 34             throw new RuntimeException("PDF生成失败", e);
 35         }
 36     }
 37 
 38     // 绘制单页表格
 39     private void drawTableForPage(PDPageContentStream contentStream, 
 40                                  List<Map<String, String>> dataList, 
 41                                  String instrumentName, 
 42                                  int currentPage, 
 43                                  int totalPages,
 44                                  int startIndex,PDFont font) throws IOException {
 45         try{
 46             
 47         // 表格参数
 48            float margin = 30;  //左边距
 49         float yStart = 700;   // 从页面顶部往下700点的位置开始绘制
 50         float rowHeight = 55; 
 51         float tableWidth = 550;
 52         float[] colWidths = {30, 80, 120, 80, 80,60,100}; // 列宽
 53         
 54         float nextY = yStart; 
 55         
 56         // 绘制页眉信息
 57           drawPageHeader(contentStream, instrumentName, currentPage, totalPages, margin, nextY, font);
 58         // 表头
 59         String[] headers = {"序号", " 日期", " 地址"," 项目"," 状态", "使用人", " 编号"};
 60        
 61         // 绘制表头背景 
 62         contentStream.setNonStrokingColor(200, 200, 200); // 灰色背景
 63         contentStream.addRect(margin, nextY - rowHeight, tableWidth, rowHeight);
 64         contentStream.fill();
 65         contentStream.setNonStrokingColor(0, 0, 0); // 恢复黑色
 66         
 67         // 表头文字
 68         float textX = margin;
 69         contentStream.beginText();
 70         contentStream.setFont(font, 12);
 71         contentStream.newLineAtOffset(textX + 5, nextY - rowHeight + 20);
 72         
 73         for (int i = 0; i < headers.length; i++) {
 74             contentStream.showText(headers[i]);
 75             contentStream.newLineAtOffset(colWidths[i], 0);
 76         }
 77         contentStream.endText();
 78         
 79         nextY -= rowHeight;    //减去这部分行高,向下定位
 80          
 81         // 绘制当前页的数据行
 82           for (int i = 0; i < dataList.size(); i++) {
 83                 Map<String, String> data = dataList.get(i);
 84             int globalIndex = startIndex + i; // 全局序号
 85             
 86            
 87             float currentY = nextY - rowHeight;
 88             float textVerticalOffset = rowHeight * 0.6f;
 89             
 90             // 绘制数据内容 - 使用全局序号
 91             contentStream.beginText();
 92             contentStream.setFont(font, 9);
 93             contentStream.newLineAtOffset(margin + 10, currentY + textVerticalOffset);
 94             contentStream.showText(String.valueOf(globalIndex + 1)); // 全局序号
 95             contentStream.endText();
 96             
 97             //  日期
 98             String syrq = data.get("syrq");
 99             float syrqX = margin + colWidths[0]  + 5;
100             float syrqWidth = colWidths[1] - 10; // 留出边距
101             drawWrappedText(contentStream, syrq, font, 9, syrqX, currentY + 35, syrqWidth, 12);
102              
103             //  地址
104             String sjdw = data.get("sydz");
105             float addressX = margin + colWidths[0] + colWidths[1] + 5;
106             float addressWidth = colWidths[2] - 10; // 留出边距
107             drawWrappedText(contentStream, sjdw, font, 9, addressX, currentY + 35, addressWidth, 12);
108             
109             //  项目
110             String sbmc = data.get("syxm");
111             float projectX = margin + colWidths[0] + colWidths[1] + colWidths[2] + 5;
112             float projectWidth = colWidths[3] - 10;
113             drawWrappedText(contentStream, sbmc, font, 9, projectX, currentY + 35, projectWidth, 12);
114 
115             //  状态
116             String xnzt = data.get("xnzt");
117             float xnztX = margin + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + 5;
118             float xnztWidth = colWidths[3] - 10;
119             drawWrappedText(contentStream, xnzt, font, 9, xnztX, currentY + 35, xnztWidth, 12);
120             
121             // 使用人
122             String syr = data.get("syr");
123             float syrX = margin + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4] + 5;
124             float syrWidth = colWidths[3] - 10;
125             drawWrappedText(contentStream, syr, font, 9, syrX, currentY + 35, syrWidth, 12);
126              
127             //  编号
128             String bh = data.get("bh");
129             float bhX = margin + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4] + colWidths[5] + 5;
130             float bhWidth = colWidths[3] - 10;
131             drawWrappedText(contentStream, bh, font, 9, bhX, currentY + 35, bhWidth, 12); 
132             
133             nextY -= rowHeight;
134              // 绘制边框
135            contentStream.setStrokingColor(0, 0, 0); // 边框颜色
136            contentStream.addRect(margin, nextY, tableWidth, yStart - nextY);
137            contentStream.stroke();
138            drawTableInnerBorders(contentStream, margin, yStart, tableWidth, rowHeight, colWidths, dataList.size() + 1);
139           
140             
141             // 检查页面底部,避免内容超出
142             if (nextY < 100) {
143                 break;
144             }
145         } 
146          
147         // 绘制表格外边框
148          contentStream.setStrokingColor(0, 0, 0);
149         contentStream.setLineWidth(1.5f);
150         float tableBottom = nextY + (dataList.size() * rowHeight); // 计算表格底部位置
151         contentStream.addRect(margin, tableBottom, tableWidth, yStart  - tableBottom);
152         contentStream.stroke();  
153       
154         
155         }catch(Exception e){
156             e.printStackTrace();
157         }
158     }
159      
160 
161     // 绘制页眉
162     private void drawPageHeader(PDPageContentStream contentStream, 
163                                String instrumentName, 
164                                int currentPage, 
165                                int totalPages,
166                                float margin, 
167                                float yStart,
168                                PDFont chineseFont) throws IOException {
169         
170         // 主标题
171         contentStream.beginText();
172         contentStream.setFont(chineseFont, 16);
173         contentStream.newLineAtOffset(margin+180, yStart+50);
174         contentStream.showText("xx设备使用记录表");
175         contentStream.endText();
176         
177         // 仪器名称
178         String generateTime = "                  生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
179         contentStream.beginText();
180         contentStream.setFont(chineseFont, 12);
181         contentStream.newLineAtOffset(margin, yStart+20 );
182         contentStream.showText("设备名称: " + instrumentName);
183         contentStream.showText(generateTime);
184         contentStream.endText();
185         
186         // 页码信息
187         String pageInfo = "第 " + currentPage + " 页 / 共 " + totalPages + " 页";
188         contentStream.beginText();
189         contentStream.setFont(chineseFont, 10);
190         contentStream.newLineAtOffset(margin + 430, yStart + 20); // 右对齐
191         contentStream.showText(pageInfo);
192         contentStream.endText();
193          
194     }
195 
196      
197     // 文本换行辅助方法
198      private List<String> wrapText(String text, PDFont font, float fontSize, float maxWidth) throws IOException {
199          List<String> lines = new ArrayList<>();
200          if (text == null || text.isEmpty()) {
201              lines.add("");
202              return lines;
203          }
204          
205          // 按字符分割,支持中文
206          List<String> words = new ArrayList<>();
207          for (int i = 0; i < text.length(); i++) {
208              words.add(String.valueOf(text.charAt(i)));
209          }
210          
211          StringBuilder currentLine = new StringBuilder();
212          float currentWidth = 0;
213          
214          for (String word : words) {
215              float wordWidth = font.getStringWidth(word) * fontSize / 1000;
216              
217              // 如果当前行加上这个词不超过最大宽度
218              if (currentWidth + wordWidth <= maxWidth) {
219                  currentLine.append(word);
220                  currentWidth += wordWidth;
221              } else {
222                  // 换行
223                  if (currentLine.length() > 0) {
224                      lines.add(currentLine.toString());
225                  }
226                  currentLine = new StringBuilder(word);
227                  currentWidth = wordWidth;
228              }
229          }
230          
231          // 添加最后一行
232          if (currentLine.length() > 0) {
233              lines.add(currentLine.toString());
234          }
235          
236          return lines;
237      }
238      
239      private void drawWrappedText(PDPageContentStream contentStream, String text, PDFont font, float fontSize, 
240              float x, float y, float maxWidth, float lineHeight) throws IOException {
241             List<String> lines = wrapText(text, font, fontSize, maxWidth);
242             
243             for (int i = 0; i < lines.size(); i++) {
244             contentStream.beginText();
245             contentStream.setFont(font, fontSize);
246             contentStream.newLineAtOffset(x, y - (i * lineHeight));
247             contentStream.showText(lines.get(i));
248             contentStream.endText();
249             }
250          }
251      
252     // 绘制表格内边框(横线和竖线)
253      private void drawTableInnerBorders(PDPageContentStream contentStream, 
254                                        float margin, float yStart, float tableWidth, 
255                                        float rowHeight, float[] colWidths, int rowCount) throws IOException {
256          
257          float currentY = yStart;
258          
259          // 绘制所有横线
260          contentStream.setStrokingColor(150, 150, 150);
261          contentStream.setLineWidth(0.5f);
262          
263          for (int i = 0; i <= rowCount; i++) {
264              contentStream.moveTo(margin, currentY);
265              contentStream.lineTo(margin + tableWidth, currentY);
266              contentStream.stroke();
267              currentY -= rowHeight;
268          }
269          
270          // 绘制所有竖线
271          float currentX = margin;
272          contentStream.setStrokingColor(150, 150, 150);
273          contentStream.setLineWidth(0.5f);
274          
275          // 绘制列之间的竖线
276          for (int i = 0; i <= colWidths.length; i++) {
277              contentStream.moveTo(currentX, yStart);
278              contentStream.lineTo(currentX, yStart - (rowCount * rowHeight));
279              contentStream.stroke();
280              
281              if (i < colWidths.length) {
282                  currentX += colWidths[i];
283              }
284          }
285      }
286       
287      
288         public Map<String, Object> getAllYqybUsageData(CommonReportBean commonReportBean) {
289             Map<String, Object> result = new HashMap<>();
290             try {
291                   
292                 // 这里替换成您的数据查询逻辑
293                 List<Map<String, String>> dataList = new ArrayList<>();
294                 
295                 // 示例数据
296                  Map<String, String> data = new HashMap<>();
297                 data.put("sbmc", "设备名称1");
298                 data.put("glbh", "管理编号2");
299                 data.put("syrq", "实验日期3");
300                 data.put("sydz", "使用地址4");
301                 data.put("syxm", "试验项目5");
302                 data.put("xnzt", "性能状态6");
303                 data.put("syr", "张三");
304                 data.put("bh", "BG20240001");
305                 dataList.add(data); 
306                 
307                 result.put("success", true);
308                 result.put("data", dataList);
309                 result.put("total", dataList.size());
310                 
311             } catch (Exception e) {
312                 result.put("success", false);
313                 result.put("message", e.getMessage());
314             }
315             return result;
316         }
317         
View Code

 

控制层这部分代码可以不用管

 1    @RequestMapping(value = "/printpdf", method = {RequestMethod.GET, RequestMethod.POST})
 2     public void printpdf(  HttpServletResponse response) {
 3         try {
 4                  // 1.省略.....
 5             //dataList.... instrumentName... 
 6             // 2. 生成PDF
 7             byte[] pdfBytes = utilService.generatePdf(dataList, instrumentName);
 8           
 9             response.reset(); // 重要:重置响应
10             response.setContentType("application/pdf");
11             response.setCharacterEncoding("UTF-8");
12             response.setHeader("Content-Disposition", "attachment; filename=report.pdf");
13             response.setHeader("Content-Length", String.valueOf(pdfBytes.length));
14             response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
15             response.setHeader("Pragma", "no-cache");
16             response.setDateHeader("Expires", 0);
17             
18             // 4. 输出PDF
19             ServletOutputStream out = response.getOutputStream();
20             out.write(pdfBytes);
21             out.flush();
22             out.close();
23             
24         } catch (Exception e) {
25             e.printStackTrace();
26             try {
27                 response.setContentType("text/html;charset=UTF-8");
28                 response.getWriter().write("PDF生成失败:" + e.getMessage());
29             } catch (IOException ex) {
30                 ex.printStackTrace();
31             }
32         }
33     }
View Code

 

 

生成结果:↓

image

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年11月呼叫中心系统五大品牌权威发布:提升服务效率的核心技术深度评测

一、行业格局分析 根据中国信息通信研究院发布的2024年云计算与呼叫中心产业报告,中国呼叫中心系统市场规模在2023年达到285亿元,同比增长12.5%,预计2025年将突破350亿元。企业数字化转型加速推动云呼叫中心需求增长…

2025年11月智能AI客服服务商品牌排行榜出炉:聚焦大模型能力与低延迟交互技术路线

行业格局分析 根据中国信通院发布的2024年智能客服行业研究报告,全球智能AI客服市场规模预计在2025年达到1200亿元,年复合增长率超过30%。企业数字化转型加速和客户服务自动化需求激增是主要驱动因素。用户对智能客服…

2025年11月沈阳酒店深度解析:从区位到服务的全维度评测

行业格局分析 根据中国旅游研究院发布的《2024年中国城市住宿业发展报告》,沈阳作为东北地区重要的交通枢纽和历史文化名城,酒店市场规模持续增长,2023年全市酒店接待旅客量同比增长12%,中高端酒店需求显著提升。随…

2025年评价高的化工离心泵最新TOP厂家排名

2025年评价高的化工离心泵最新TOP厂家排名行业背景与市场趋势化工离心泵作为化工生产过程中的核心设备之一,其性能和质量直接关系到生产效率和安全性。随着全球化工产业向智能化、高效化、环保化方向发展,2025年的化…

2025年11月呼叫中心系统五大品牌权威发布:提升客户体验的核心技术评测(

根据中国信息通信研究院发布的2024年云计算市场研究报告显示,中国呼叫中心系统市场规模达到285亿元,同比增长18.5%。随着企业数字化转型加速,智能客服需求持续增长,云端部署模式占比已超过60%。行业正从传统硬件部…

【NCS随笔】使用UICR寄存器保存数据

nRF54L15使用UICR寄存器保存数据 本文章主要是讲解如何使用nRF54L15的UICR寄存器保存一些基础数据一、UICR寄存器的说明 UICR(用户信息配置寄存器)**是非易失性存储器(NVM)寄存器,用于配置用户特定的设置 注意所有…

2025年深圳急救车租赁公司权威推荐榜单:救护车租赁‌/私人救护车出租‌/出租救护车源头公司精选

在医疗服务需求多元化与人口老龄化趋势加速的背景下,深圳急救车租赁服务市场正经历着从基础运输向专业化、分级化的转型升级。行业数据显示,2024年中国救护车租赁市场规模已达约25亿元,其中深圳地区的需求占比显著提…

2025年11月呼叫中心系统品牌排行榜出炉:聚焦AI技术赋能与智能化升级路径

根据中国信息通信研究院发布的《2024年中国客服中心市场研究报告》显示,2024年中国呼叫中心系统市场规模达到285亿元,同比增长12.3%。随着企业数字化转型加速,智能客服渗透率从2023年的35%提升至2024年的42%,AI技术…

2025年口碑好的160℃脱硝催化剂行业内口碑厂家排行榜

2025年口碑好的160℃脱硝催化剂行业内口碑厂家排行榜行业背景与市场趋势随着全球环保法规日益严格和"双碳"目标的推进,脱硝催化剂作为烟气治理的核心材料,市场需求持续增长。160℃低温脱硝催化剂因其在低温…

【Nordic随笔】蓝牙6.2核心规范概述

蓝牙6.2核心规范概述 2025年11月份蓝牙联盟发布了一项重要更新,主要在安全性,低延迟上面实现了新的突破参考文献:https://www.bluetooth.com/blog/just-released-bluetooth-core-6-2/ 一、连接性能 蓝牙连接间隔缩短…

2025宝宝益生菌权威榜单发布:葆婴益生菌领衔,定义儿童肠道健康新标准

在现代育儿理念中,肠道健康被视为儿童免疫力、营养吸收与生长发育的核心。随着益生菌市场的快速发展,产品良莠不齐、宣传夸大、菌株虚标等问题日益突出。根据《2025年中国婴幼儿营养补充品消费白皮书》数据显示,超过…

2025年知名的超临界CO₂萃取热门厂家推荐榜单

2025年知名的超临界CO₂萃取热门厂家推荐榜单行业背景与市场趋势超临界CO₂萃取技术作为一种绿色环保的分离技术,近年来在食品、医药、化妆品、环保等领域的应用日益广泛。随着全球对绿色化学和可持续发展理念的重视,…

NBA 常规赛实战竞争力深化与核心品质升级:球队竞技效能提升

2025-11-27 15:46:47 NBA 常规赛实战竞争力深化与核心品质升级:球队竞技效能提升|@cPj.GzShAnGYuAn.cOm@||@cPk.SdDxTgGc.cOm@||@cPl.sDdXtGgC.COM@||@cPm.SdDxTgGc.cOm@||@cPn.sDdXtGgC.COM@||@cPo.SdDxTgGc.cOm@||@…

NBA 常规赛核心竞争力升级与实战效能深化:球队竞技潜力释放

2025-11-27 15:38:38 NBA 常规赛核心竞争力升级与实战效能深化:球队竞技潜力释放|@cNb.ScZuOaN.cOm@||@cNc.DgMgX.cOm@||@cNd.dGmGx.COM@||@cNe.DgMgX.cOm@||@cNf.dGmGx.COM@||@cNg.DgMgX.cOm@||@cNh.dGmGx.COM@||@cN…

2025年11月上海审计事务所选择指南:主流机构排行榜分析

在上海这座经济活跃、创新企业密集的国际化都市,许多企业管理者、创业者和财务负责人在日常经营中面临着复杂的财税合规需求。随着2025年临近,上海审计服务市场呈现出专业化、细分化的明显趋势。根据国家财政部门最新…

2025年评价高的风管防火阀厂家推荐及选购参考榜

2025年评价高的风管防火阀厂家推荐及选购参考榜行业背景与市场趋势随着建筑安全标准的不断提高和消防法规的日益严格,风管防火阀作为建筑消防系统中的关键部件,其市场需求持续增长。2025年,中国防火阀市场规模预计将…

NBA 常规赛核心品质深化与实战竞争力升级:球队竞技水平进阶

2025-11-27 15:44:04 NBA 常规赛核心品质深化与实战竞争力升级:球队竞技水平进阶|@cOp.GsJjH.cOm@||@cOq.gSjJh.COM@||@cOr.GsJjH.cOm@||@cOs.gSjJh.COM@||@cOt.GsJjH.cOm@||@cOu.gSjJh.COM@||@cOv.GzShAnGYuAn.cOm@|…

2025年11月高新技术企业认定公司推荐榜单:主流机构综合对比与选择指南

在科技创新驱动发展的时代背景下,越来越多的企业将高新技术企业认定视为提升核心竞争力、享受政策红利的重要途径。对于广大科技型中小企业而言,专业的高新技术企业认定服务能够有效帮助企业梳理创新成果、规范财务管…

2025年中国水处理与防火材料公司推荐:德美化工水处理药剂公

本榜单依托全维度市场调研与真实行业口碑,深度筛选出十家在水处理与防火材料领域兼具技术实力与市场认可度的标杆企业,为企业选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:廊坊德美化工防火材料有限公…

2025年深圳亚马逊UL报告公司权威推荐榜单:ISO体系认证‌/中国SRRC认证‌/IP65防尘防水测试源头公司家精选

在全球电商平台合规要求日益严格的背景下,亚马逊UL测试报告已成为电子产品、家电类目入驻的必备资质。据行业统计数据显示,2024年深圳地区检测认证服务市场规模已达85亿元,其中跨境电商产品检测业务年增长率稳定在1…