java生成PDF(图片,模板,表格)

矫情吗;* 2023-10-02 22:49 140阅读 0赞

刚接到了一个需求,生成一个pdf,一开始以为挺简单的,通过模板生成嘛,我也发过相应的文章,根据模板直接生成pdf,响应到前端或者根据模板生成pdf,直接指定下载位置,这两种方案都可以,不过这篇文章主要讲的生成的pdf是既有模板填充还需要自己动态生成表格,包括还需要通过java去生成Echarts图形,通过java后台生成Echarts图形我专门写了一篇文章介绍,java后台生成统计图,这个生成统计图的文章中有两种生成统计图的方式,可以自己选择。

本篇文章的重点还是在讲通过java生成pdf,其实如果是单纯的模板填充挺简单的,但是又要填充模板还要动态生成表格就比较麻烦了,因为如果在模板中画表格的框去生成的话,超过模板框的位置就会隐藏,我刚接到需求的时候也是有点难受,在网上也是找了大量的资料,研究了半天,发现好多都是你粘贴我,我粘贴你,最终我也算是搞成了,把这些整合一下,让大家用的好用一些,废话不多说,直接上代码!

这里说一下啊,如果需要生成echarts图片,先去看我的生成echarts图片文章,不然这个搞不了。

最近很多人都找我要模板链接,我把他放到网盘了,需要的可以去下载https://pan.baidu.com/s/1YJZtLdiySxUry4h2Gd1V7g
提取码:j1l5,不想从网盘下的也可以从的我csdn资源里面下载,资源里面我也放了一份,0积分下载的,大家自取就好。

一、pom依赖

首先先引入咱们需要的pom依赖,我这里只粘贴pdf的吧,lombok和hutool经常用我就不粘贴了。

  1. <dependency>
  2. <groupId>com.itextpdf</groupId>
  3. <artifactId>itextpdf</artifactId>
  4. <version>5.5.9</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.itextpdf</groupId>
  8. <artifactId>itext-asian</artifactId>
  9. <version>5.2.0</version>
  10. </dependency>

二、生成pdf,模板和图片及动态生成表格

我这个没有搞页眉,只搞了页脚,设置页眉/页脚和水印的类我会在最后粘贴出来,因为这几个案例用的都是一个配置类。

实体类
  1. package com.example.demo.domain;
  2. import lombok.Data;
  3. import lombok.experimental.Accessors;
  4. import java.math.BigDecimal;
  5. @Data
  6. @Accessors(chain = true)
  7. public class DuizhangDomain {
  8. private String jg;
  9. private Integer ydz;
  10. private Integer wdz;
  11. private BigDecimal dzl;
  12. }
  13. package com.example.demo.domain;
  14. import lombok.Data;
  15. import lombok.experimental.Accessors;
  16. import java.io.Serializable;
  17. @Data
  18. @Accessors(chain = true)
  19. public class YqTable implements Serializable {
  20. private String jg;
  21. private Integer yqs;
  22. }
生成pdf代码
  1. import cn.hutool.core.date.DateUtil;
  2. import com.example.demo.domain.DuizhangDomain;
  3. import com.example.demo.domain.YqTable;
  4. import com.example.demo.pdf.phantom.App;
  5. import com.example.demo.pdf.phantom.PageEvent;
  6. import com.itextpdf.text.*;
  7. import com.itextpdf.text.pdf.*;
  8. import freemarker.template.TemplateException;
  9. import org.springframework.core.io.ClassPathResource;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.ByteArrayOutputStream;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.io.OutputStream;
  15. import java.math.BigDecimal;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * 根据模板填充数据及图片,动态生成数据列表
  20. */
  21. public class CreatePdfEchrtsAndTableMain2 {
  22. private final static String TITLE = "这个是标题,可有可无";
  23. public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {
  24. //设置请求返回类型
  25. response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");
  26. OutputStream outputStream = response.getOutputStream();
  27. //模板路径,放到项目里用这个ClassPathResource
  28. ClassPathResource classPathResource = new ClassPathResource("templates/test1.pdf");
  29. InputStream inputStream = classPathResource.getInputStream();
  30. PdfReader reader = new PdfReader(inputStream);
  31. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  32. PdfStamper ps = new PdfStamper(reader, bos);
  33. //设置字体
  34. final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  35. ArrayList<BaseFont> fontList = new ArrayList<>();
  36. fontList.add(font);
  37. //提取表单,这个是模板画好的文本框
  38. AcroFields s = ps.getAcroFields();
  39. s.setSubstitutionFonts(fontList);
  40. s.setFieldProperty("jrfk","textfont",font,null);
  41. s.setFieldProperty("bjzs","textfont",font,null);
  42. s.setFieldProperty("type","textfont",font,null);
  43. s.setFieldProperty("createTime","textfont",font,null);
  44. s.setFieldProperty("title","textfont",font,null);
  45. s.setField("jrfk","10");
  46. s.setField("bjzs","20");
  47. s.setField("type","日报");
  48. s.setField("createTime", DateUtil.now());
  49. s.setField("title", TITLE);
  50. //添加图片
  51. PdfContentByte cb = ps.getOverContent(1);
  52. //添加logo
  53. Rectangle logo = s.getFieldPositions("logo").get(0).position;
  54. Image logoImage = Image.getInstance("https://img1.baidu.com/it/u=3646261857,3326755268&fm=253&app=138&size=w931&n=0&f=JPG&fmt=auto?sec=1668186000&t=20050fc88fc3feb1f9d28392f4595ec6");
  55. //根据域的大小缩放图片,我这里宽度在原有的域基础上加了100,你们可以自己调节
  56. logoImage.scaleToFit(logo.getWidth() + 100,logo.getHeight());
  57. logoImage.setAlignment(Image.MIDDLE);
  58. logoImage.setAbsolutePosition(logo.getLeft(),logo.getBottom());
  59. cb.addImage(logoImage);
  60. //获取统计图
  61. //获取域
  62. Rectangle rlt = s.getFieldPositions("rlt").get(0).position;
  63. //热力图
  64. Image rltImage = Image.getInstance("https://img0.baidu.com/it/u=4043177345,1055141017&fm=253&app=138&size=w931&n=0&f=PNG&fmt=auto?sec=1668186000&t=8cfdc5c95cc0070eb91946d780ee8dc3");
  65. //根据域大小设置缩放图片
  66. rltImage.scaleToFit(rlt.getWidth() + 100,rlt.getHeight());
  67. // 设置居中
  68. rltImage.setAlignment(Image.MIDDLE);
  69. //绝对定位
  70. rltImage.setAbsolutePosition(rlt.getLeft(),rlt.getBottom());
  71. //图片旋转,这个可以将图片进行一个旋转,看自己需求
  72. // rltImage.setRotationDegrees(90);
  73. cb.addImage(rltImage);
  74. //按机构统计图
  75. //这个是生成echarts的类,如果需要生成echarts可以去看我的另一个文章,上面前言已经提到了
  76. App app1 = new App();
  77. byte[] echarts1 = app1.createEcharts("ajg.ftl");
  78. Image ajgImage = Image.getInstance(echarts1);
  79. Rectangle ajg = s.getFieldPositions("ajg").get(0).position;
  80. // 根据域大小设置缩放图片
  81. ajgImage.scaleToFit(ajg.getWidth(),400);
  82. // 设置居中
  83. ajgImage.setAlignment(Image.MIDDLE);
  84. // 绝对定位
  85. ajgImage.setAbsolutePosition(ajg.getLeft(),ajg.getBottom());
  86. cb.addImage(ajgImage);
  87. //按机构排名,这个是在图片的基础上还要添加数据,这个模板可以画好
  88. for (int i = 1; i <= 3; i++) {
  89. s.setFieldProperty("ajg" + i,"textfont",font,null);
  90. s.setField("ajg" + i,"机构" + i);
  91. }
  92. App app = new App();
  93. byte[] echarts = app.createEcharts("option.ftl");
  94. //按业务
  95. Rectangle ayw = s.getFieldPositions("ayw").get(0).position;
  96. Image aywImage = Image.getInstance(echarts);
  97. // 设根据域大小设置缩放图片
  98. aywImage.scaleToFit(ayw.getWidth(), 400);
  99. // 设置居中
  100. aywImage.setAlignment(Image.MIDDLE);
  101. // 绝对定位
  102. aywImage.setAbsolutePosition(ayw.getLeft(),ayw.getBottom());
  103. cb.addImage(aywImage);
  104. //按业务排名
  105. for (int i = 1; i <= 3; i++) {
  106. s.setFieldProperty("ayw" + i,"textfont",font,null);
  107. s.setField("ayw" + i,"机构" + i);
  108. }
  109. //按场合
  110. Rectangle acj = s.getFieldPositions("acj").get(0).position;
  111. Image acjImage = Image.getInstance(echarts);
  112. // 设根据域大小设置缩放图片
  113. acjImage.scaleToFit(acj.getWidth(), 400);
  114. // 设置居中
  115. acjImage.setAlignment(Image.MIDDLE);
  116. // 绝对定位
  117. acjImage.setAbsolutePosition(acj.getLeft(),acj.getBottom());
  118. cb.addImage(acjImage);
  119. //按场景排名
  120. for (int i = 1; i <= 3; i++) {
  121. s.setFieldProperty("acj" + i,"textfont",font,null);
  122. s.setField("acj" + i,"机构" + i);
  123. }
  124. //按等级
  125. Rectangle adj = s.getFieldPositions("adj").get(0).position;
  126. Image adjImage = Image.getInstance(echarts);
  127. // 设根据域大小设置缩放图片
  128. adjImage.scaleToFit(adj.getWidth(),400);
  129. // 设置居中
  130. adjImage.setAlignment(Image.MIDDLE);
  131. // 绝对定位
  132. adjImage.setAbsolutePosition(adj.getLeft(),adj.getBottom());
  133. cb.addImage(adjImage);
  134. //按场景排名
  135. for (int i = 1; i <= 3; i++) {
  136. s.setFieldProperty("adj" + i,"textfont",font,null);
  137. s.setField("adj" + i,"机构" + i);
  138. }
  139. ps.setFormFlattening(true);
  140. ps.close();
  141. //*******************填充编辑好后的pdf**************
  142. reader = new PdfReader(bos.toByteArray());
  143. Rectangle pageSize = reader.getPageSize(1);
  144. Document document = new Document(pageSize);
  145. PdfWriter writer = PdfWriter.getInstance(document, outputStream);
  146. writer.setPageEvent(new PageEvent());
  147. // 打开文档
  148. document.open();
  149. PdfContentByte cbUnder = writer.getDirectContentUnder();
  150. PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);
  151. cbUnder.addTemplate(pageTemplate, 0, 0);
  152. //重新开一页面
  153. document.newPage();
  154. createTable(writer,document);
  155. // document.newPage();
  156. createTableYq(writer,document);
  157. document.close();
  158. outputStream.close();
  159. }
  160. //为一个表格添加内容
  161. public PdfPCell createSetCell(String value,Font font){
  162. PdfPCell cell = new PdfPCell();
  163. cell.setPhrase(new Phrase(value,font));
  164. cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  165. cell.setHorizontalAlignment(Element.ALIGN_CENTER);
  166. return cell;
  167. }
  168. //添加表格
  169. public void createTable(PdfWriter writer,Document document) throws DocumentException, IOException {
  170. PdfPTable table = new PdfPTable(new float[] {
  171. 30, 80, 50, 50, 50});
  172. table.setTotalWidth(520);
  173. table.setPaddingTop(500);
  174. table.setLockedWidth(true);
  175. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  176. table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());
  177. //每页都显示表头,输入几就是第几行的表头固定
  178. table.setHeaderRows(2);
  179. table.setHeaderRows(3);
  180. //定义数据的字体
  181. BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
  182. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  183. PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
  184. cell.setHorizontalAlignment( Element.ALIGN_LEFT);
  185. cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
  186. cell.setBorder(Rectangle.NO_BORDER);
  187. cell.setColspan(5);
  188. table.addCell(cell);
  189. //表头信息
  190. PdfPCell heandCell = new PdfPCell();
  191. heandCell.setRowspan(1);
  192. heandCell.setColspan(5);
  193. heandCell.setFixedHeight(60);
  194. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  195. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  196. heandCell.setPhrase(new Phrase(TITLE + "对账情况表",textFont));
  197. table.addCell(heandCell);
  198. //表字段
  199. String title[] = {
  200. "序号","机构","已对账","未对账","对账率%"};
  201. for (int i = 0; i < title.length; i++) {
  202. PdfPCell heardCell = new PdfPCell();
  203. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  204. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  205. heardCell.setPhrase(new Phrase(title[i], textFont));
  206. heardCell.setMinimumHeight(20);
  207. table.addCell(heardCell);
  208. }
  209. //列表数据
  210. List<DuizhangDomain> duizhangDomains = new ArrayList<>();
  211. for (int i = 1; i <= 1000; i++) {
  212. DuizhangDomain duizhangDomain = new DuizhangDomain();
  213. duizhangDomain.setJg("机构" + i).setYdz(i).setWdz(i).setDzl(new BigDecimal(i));
  214. duizhangDomains.add(duizhangDomain);
  215. }
  216. for (int i = 0; i < duizhangDomains.size(); i++) {
  217. PdfPCell setCell1 = createSetCell((i + 1) + "", textFont);
  218. PdfPCell setCell2 = createSetCell(duizhangDomains.get(i).getJg(), textFont);
  219. PdfPCell setCell3 = createSetCell(duizhangDomains.get(i).getYdz().toString(), textFont);
  220. PdfPCell setCell4 = createSetCell(duizhangDomains.get(i).getWdz().toString(), textFont);
  221. PdfPCell setCell5 = createSetCell(duizhangDomains.get(i).getDzl() + "%", textFont);
  222. table.addCell(setCell1);
  223. table.addCell(setCell2);
  224. table.addCell(setCell3);
  225. table.addCell(setCell4);
  226. table.addCell(setCell5);
  227. }
  228. document.add(table);
  229. }
  230. public void createTableYq(PdfWriter writer,Document document) throws DocumentException, IOException {
  231. PdfPTable table = new PdfPTable(new float[] {
  232. 80, 50});
  233. table.setTotalWidth(520);
  234. table.setPaddingTop(500);
  235. table.setLockedWidth(true);
  236. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  237. table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());
  238. //每页都显示表头,输入几就是第几行的表头固定
  239. table.setHeaderRows(2);
  240. table.setHeaderRows(3);
  241. //定义数据的字体
  242. BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
  243. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  244. //这个是为了区分两个表格加的一个间隔,可以去掉
  245. PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
  246. cell.setHorizontalAlignment( Element.ALIGN_LEFT);
  247. cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
  248. cell.setBorder(Rectangle.NO_BORDER);
  249. cell.setColspan(2);
  250. table.addCell(cell);
  251. //表头信息
  252. PdfPCell heandCell = new PdfPCell();
  253. heandCell.setRowspan(1);
  254. heandCell.setColspan(2);
  255. heandCell.setFixedHeight(60);
  256. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  257. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  258. heandCell.setPhrase(new Phrase(TITLE + "逾期表",textFont));
  259. table.addCell(heandCell);
  260. //表字段
  261. String title[] = {
  262. "机构名称","逾期数"};
  263. for (int i = 0; i < title.length; i++) {
  264. PdfPCell heardCell = new PdfPCell();
  265. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  266. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  267. heardCell.setPhrase(new Phrase(title[i], textFont));
  268. heardCell.setMinimumHeight(20);
  269. table.addCell(heardCell);
  270. }
  271. //列表数据
  272. List<YqTable> yqTables = new ArrayList<>();
  273. for (int i = 1; i <= 1000; i++) {
  274. YqTable yq = new YqTable();
  275. yq.setJg("逾期机构" + i).setYqs(i);
  276. yqTables.add(yq);
  277. }
  278. for (int i = 0; i < yqTables.size(); i++) {
  279. PdfPCell setCell2 = createSetCell(yqTables.get(i).getJg(), textFont);
  280. PdfPCell setCell3 = createSetCell(yqTables.get(i).getYqs().toString(), textFont);
  281. table.addCell(setCell2);
  282. table.addCell(setCell3);
  283. }
  284. document.add(table);
  285. }
  286. }

我说一下这个生成pdf需要注意的点,可能有的朋友很疑惑为什么要调用document.newPage(); 新开一页,这个是因为,如果你不新开一页的话会导致你动态生成的表格会跟模板内容重叠,注意是重叠而不是覆盖!!!
新开一页的话,就相当于我在第二页开始动态生成表格,这个时候可能有朋友就要问了,那如果我的模板没有占到一页怎么办,这样第一页岂不是会有空白,这个问题我也想到了,因为我的需求是生成好几种不同的pdf,下面我会把这种情况如何生成的代码放出来,我们先看一下第一种生成出来后的结果,我测的数据比较多,就粘几个结果好了。

生成结果示例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这就是结果!!!!基本上还可以

三、生成pdf,模板和动态表格

实体类都是一样的没有变。

生成pdf代码
  1. package com.example.demo.pdf;
  2. import cn.hutool.core.date.DateUtil;
  3. import com.example.demo.domain.DuizhangDomain;
  4. import com.example.demo.domain.YqTable;
  5. import com.example.demo.pdf.phantom.PageEvent;
  6. import com.itextpdf.text.*;
  7. import com.itextpdf.text.pdf.*;
  8. import freemarker.template.TemplateException;
  9. import org.springframework.core.io.ClassPathResource;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.ByteArrayOutputStream;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.io.OutputStream;
  15. import java.math.BigDecimal;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * 模板第一页不占满,生成表格
  20. */
  21. public class CreatePdfEchrtsAndTableMain3 {
  22. public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {
  23. //设置请求返回类型
  24. response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");
  25. OutputStream outputStream = response.getOutputStream();
  26. //模板路径,放到项目里用这个ClassPathResource
  27. ClassPathResource classPathResource = new ClassPathResource("templates/test3.pdf");
  28. InputStream inputStream = classPathResource.getInputStream();
  29. PdfReader reader = new PdfReader(inputStream);
  30. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  31. PdfStamper ps = new PdfStamper(reader, bos);
  32. //设置字体
  33. final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  34. ArrayList<BaseFont> fontList = new ArrayList<>();
  35. fontList.add(font);
  36. //提取表单
  37. AcroFields s = ps.getAcroFields();
  38. s.setSubstitutionFonts(fontList);
  39. s.setFieldProperty("type", "textfont", font, null);
  40. s.setFieldProperty("createTime", "textfont", font, null);
  41. s.setFieldProperty("title", "textfont", font, null);
  42. s.setField("type", "日报");
  43. s.setField("createTime", DateUtil.now());
  44. s.setField("title", "这是title,模板画的位置框");
  45. ps.setFormFlattening(true);
  46. ps.close();
  47. //*******************填充编辑好后的pdf**************
  48. reader = new PdfReader(bos.toByteArray());
  49. Rectangle pageSize = reader.getPageSize(1);
  50. Document document = new Document(pageSize);
  51. PdfWriter writer = PdfWriter.getInstance(document, outputStream);
  52. writer.setPageEvent(new PageEvent());
  53. // 打开文档
  54. document.open();
  55. PdfContentByte cbUnder = writer.getDirectContentUnder();
  56. PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);
  57. cbUnder.addTemplate(pageTemplate, 0, 0);
  58. //添加间隙,这里为进行了一个封装,因为这个模板第一页只有一些title啥的,
  59. //重开一页太浪费,只需要确定表格要在什么位置生成,添加一个间隙就可以了
  60. createBlankTable(writer, document, font, 180);
  61. createTable(writer, document);
  62. createBlankTable(writer, document, font, 20);
  63. createTableYq(writer, document);
  64. document.close();
  65. outputStream.close();
  66. }
  67. //为一个表格添加内容
  68. public PdfPCell createSetCell(String value, Font font) {
  69. PdfPCell cell = new PdfPCell();
  70. cell.setPhrase(new Phrase(value, font));
  71. cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  72. cell.setHorizontalAlignment(Element.ALIGN_CENTER);
  73. return cell;
  74. }
  75. //添加表格
  76. public void createTable(PdfWriter writer, Document document) throws DocumentException, IOException {
  77. PdfPTable table = new PdfPTable(new float[]{
  78. 30, 80, 50, 50, 50});
  79. table.setTotalWidth(520);
  80. table.setPaddingTop(500);
  81. table.setLockedWidth(true);
  82. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  83. table.writeSelectedRows(0, -1, 500, 800, writer.getDirectContentUnder());
  84. //每页都显示表头,输入几就是第几行的表头固定
  85. table.setHeaderRows(1);
  86. table.setHeaderRows(2);
  87. //定义数据的字体
  88. BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  89. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  90. //表头信息
  91. PdfPCell heandCell = new PdfPCell();
  92. heandCell.setRowspan(1);
  93. heandCell.setColspan(5);
  94. heandCell.setFixedHeight(30);
  95. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  96. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  97. heandCell.setPhrase(new Phrase("对账情况表", textFont));
  98. table.addCell(heandCell);
  99. //表字段
  100. String title[] = {
  101. "序号", "机构", "已对账", "未对账", "对账率%"};
  102. for (int i = 0; i < title.length; i++) {
  103. PdfPCell heardCell = new PdfPCell();
  104. heardCell.setRowspan(1);
  105. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  106. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  107. heardCell.setPhrase(new Phrase(title[i], textFont));
  108. heardCell.setMinimumHeight(20);
  109. table.addCell(heardCell);
  110. }
  111. //列表数据
  112. List<DuizhangDomain> duizhangDomains = new ArrayList<>();
  113. for (int i = 1; i <= 1000; i++) {
  114. DuizhangDomain duizhangDomain = new DuizhangDomain();
  115. duizhangDomain.setJg("机构" + i).setYdz(i).setWdz(i).setDzl(new BigDecimal(i));
  116. duizhangDomains.add(duizhangDomain);
  117. }
  118. for (int i = 0; i < duizhangDomains.size(); i++) {
  119. PdfPCell setCell1 = createSetCell((i + 1) + "", textFont);
  120. PdfPCell setCell2 = createSetCell(duizhangDomains.get(i).getJg(), textFont);
  121. PdfPCell setCell3 = createSetCell(duizhangDomains.get(i).getYdz().toString(), textFont);
  122. PdfPCell setCell4 = createSetCell(duizhangDomains.get(i).getWdz().toString(), textFont);
  123. PdfPCell setCell5 = createSetCell(duizhangDomains.get(i).getDzl() + "%", textFont);
  124. table.addCell(setCell1);
  125. table.addCell(setCell2);
  126. table.addCell(setCell3);
  127. table.addCell(setCell4);
  128. table.addCell(setCell5);
  129. }
  130. document.add(table);
  131. }
  132. public void createTableYq(PdfWriter writer, Document document) throws DocumentException, IOException {
  133. PdfPTable table = new PdfPTable(new float[]{
  134. 80, 50});
  135. table.setTotalWidth(520);
  136. table.setPaddingTop(500);
  137. table.setLockedWidth(true);
  138. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  139. table.writeSelectedRows(0, -1, 500, 800, writer.getDirectContentUnder());
  140. //每页都显示表头,输入几就是第几行的表头固定
  141. table.setHeaderRows(2);
  142. table.setHeaderRows(3);
  143. //定义数据的字体
  144. BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  145. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  146. //表头信息
  147. PdfPCell heandCell = new PdfPCell();
  148. heandCell.setRowspan(1);
  149. heandCell.setColspan(2);
  150. heandCell.setFixedHeight(30);
  151. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  152. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  153. heandCell.setPhrase(new Phrase("逾期表", textFont));
  154. table.addCell(heandCell);
  155. //表字段
  156. String title[] = {
  157. "机构名称", "逾期数"};
  158. for (int i = 0; i < title.length; i++) {
  159. PdfPCell heardCell = new PdfPCell();
  160. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  161. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  162. heardCell.setPhrase(new Phrase(title[i], textFont));
  163. heardCell.setMinimumHeight(20);
  164. table.addCell(heardCell);
  165. }
  166. //列表数据
  167. List<YqTable> yqTables = new ArrayList<>();
  168. for (int i = 1; i <= 1000; i++) {
  169. YqTable yq = new YqTable();
  170. yq.setJg("逾期机构" + i).setYqs(i);
  171. yqTables.add(yq);
  172. }
  173. for (int i = 0; i < yqTables.size(); i++) {
  174. PdfPCell setCell2 = createSetCell(yqTables.get(i).getJg(), textFont);
  175. PdfPCell setCell3 = createSetCell(yqTables.get(i).getYqs().toString(), textFont);
  176. table.addCell(setCell2);
  177. table.addCell(setCell3);
  178. }
  179. document.add(table);
  180. }
  181. /**
  182. * 创建表格跟表格之间的空白间隔
  183. */
  184. public void createBlankTable(PdfWriter writer, Document document, BaseFont font, int height) throws DocumentException {
  185. PdfPTable table = new PdfPTable(new float[]{
  186. 30});
  187. table.setTotalWidth(520);
  188. table.setPaddingTop(500);
  189. table.setLockedWidth(true);
  190. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  191. table.writeSelectedRows(0, -1, 500, 800, writer.getDirectContentUnder());
  192. Font textFont = new Font(font, 10, Font.NORMAL);
  193. PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
  194. cell.setHorizontalAlignment(Element.ALIGN_LEFT);
  195. cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
  196. cell.setBorder(Rectangle.NO_BORDER);
  197. cell.setFixedHeight(height);
  198. cell.setColspan(1);
  199. table.addCell(cell);
  200. document.add(table);
  201. }
  202. }

这是第二种生成pdf的方法,生成的结果不一样,因为模板第一页没有太多的东西,所以会空出来很多空白,这个时候生成动态表格如果重开一页比较浪费,而且客户看着也不好看,所以我封装了一下生成间隙的方法,直接用间隙把模板内容和表格隔开即可,看一下效果。

生成结果示例

在这里插入图片描述
可以看到,我们在代码中并没有新开一页,只是加了一个间隙,就可以保证动态生成的表格和模板在一个页面,就此,基本上就算完成了。

页眉/页脚和水印类

  1. package com.example.demo.pdf.phantom;
  2. import com.itextpdf.text.*;
  3. import com.itextpdf.text.pdf.*;
  4. import java.io.IOException;
  5. public class PageEvent extends PdfPageEventHelper {
  6. /**
  7. * 页眉
  8. */
  9. //public String header = "itext测试页眉";
  10. /**
  11. * 文档字体大小,页脚页眉最好和文本大小一致
  12. */
  13. public int presentFontSize = 10;
  14. /**
  15. * 文档页面大小,最好前面传入,否则默认为A4纸张
  16. */
  17. public Rectangle pageSize = PageSize.A4;
  18. // 模板
  19. public PdfTemplate total;
  20. // 基础字体对象
  21. public BaseFont bf = null;
  22. // 利用基础字体生成的字体对象,一般用于生成中文文字
  23. public Font fontDetail = null;
  24. /**
  25. *
  26. * Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.
  27. *
  28. */
  29. public PageEvent() {
  30. }
  31. /**
  32. *
  33. * Creates a new instance of PdfReportM1HeaderFooter 构造方法.
  34. *
  35. * @param
  36. *
  37. * @param presentFontSize
  38. * 数据体字体大小
  39. * @param pageSize
  40. * 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
  41. */
  42. // public PDFBuilder(String yeMei, int presentFontSize, Rectangle pageSize) {
  43. // this.header = yeMei;
  44. // this.presentFontSize = presentFontSize;
  45. // this.pageSize = pageSize;
  46. // }
  47. public PageEvent( int presentFontSize, Rectangle pageSize) {
  48. this.presentFontSize = presentFontSize;
  49. this.pageSize = pageSize;
  50. }
  51. // public void setHeader(String header) {
  52. // this.header = header;
  53. // }
  54. public void setPresentFontSize(int presentFontSize) {
  55. this.presentFontSize = presentFontSize;
  56. }
  57. /**
  58. *
  59. * TODO 文档打开时创建模板
  60. *
  61. * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter,
  62. * com.itextpdf.text.Document)
  63. */
  64. public void onOpenDocument(PdfWriter writer, Document document) {
  65. total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
  66. }
  67. /**
  68. *
  69. * TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
  70. *
  71. * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,
  72. * com.itextpdf.text.Document)
  73. */
  74. public void onEndPage(PdfWriter writer, Document document) {
  75. this.addPage(writer, document);
  76. //加水印
  77. this.addWatermark(writer);
  78. }
  79. //加分页
  80. public void addPage(PdfWriter writer, Document document){
  81. //设置分页页眉页脚字体
  82. try {
  83. if (bf == null) {
  84. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
  85. }
  86. if (fontDetail == null) {
  87. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
  88. }
  89. } catch (DocumentException e) {
  90. e.printStackTrace();
  91. } catch (IOException e) {
  92. e.printStackTrace();
  93. }
  94. // 1.写入页眉
  95. // ColumnText.showTextAligned(writer.getDirectContent(),
  96. // Element.ALIGN_LEFT, new Phrase(header, fontDetail),
  97. // document.left(), document.top() + 20, 0);
  98. // 页眉添加图片
  99. // String path = ResourceUtils.getFile("classpath:").getPath();
  100. // Image img = Image.getInstance(path + "/pdfTemplates/logo.jpg");
  101. // img.setAlignment(Image.MIDDLE);
  102. // img.setWidthPercentage(80);
  103. // img.scaleToFit(50,40);
  104. // img.setAbsolutePosition(document.left(),document.top());
  105. // writer.getDirectContent().addImage(img);
  106. //页眉加下划线
  107. // PdfPTable tableHeader = new PdfPTable(1);
  108. // tableHeader.setTotalWidth(PageSize.A4.getWidth() - 60);
  109. // PdfPCell pCell = new PdfPCell();
  110. // pCell.setBorderWidthBottom(0.3f);
  111. // tableHeader.addCell(pCell);
  112. // tableHeader.writeSelectedRows(0, -1, 30, 805, writer.getDirectContent());
  113. // 2.写入前半部分的 第 X页/共
  114. int pageS = writer.getPageNumber();
  115. String foot1 = "第 " + pageS + " 页 /共";
  116. // String foot1 = pageS +"/";
  117. Phrase footer = new Phrase(foot1, fontDetail);
  118. // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
  119. float len = bf.getWidthPoint(foot1, presentFontSize);
  120. // 4.拿到当前的PdfContentByte
  121. PdfContentByte cb = writer.getDirectContent();
  122. // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
  123. // 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了
  124. // ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。
  125. ColumnText
  126. .showTextAligned(
  127. cb,
  128. Element.ALIGN_CENTER,
  129. footer,
  130. (document.rightMargin() + document.right()
  131. + document.leftMargin() - document.left() - len) / 2.0F ,
  132. document.bottom() - 20, 0);
  133. // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
  134. // len , y 轴和之前的保持一致,底边界-20
  135. cb.addTemplate(total, (document.rightMargin() + document.right()
  136. + document.leftMargin() - document.left()) / 2.0F ,
  137. document.bottom() - 20); // 调节模版显示的位置
  138. }
  139. //加水印
  140. public void addWatermark(PdfWriter writer) {
  141. // 水印图片
  142. // Image image;
  143. // try {
  144. // image = Image.getInstance("./web/images/001.jpg");
  145. // PdfContentByte content = writer.getDirectContentUnder();
  146. // content.beginText();
  147. // // 开始写入水印
  148. // for(int k=0;k<5;k++){
  149. // for (int j = 0; j <4; j++) {
  150. // image.setAbsolutePosition(150*j,170*k);
  151. // content.addImage(image);
  152. // }
  153. // }
  154. // content.endText();
  155. // } catch (IOException | DocumentException e) {
  156. // // TODO Auto-generated catch block
  157. // e.printStackTrace();
  158. // }
  159. BaseFont font = null;
  160. try {
  161. font = BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  162. } catch (DocumentException e) {
  163. e.printStackTrace();
  164. } catch (IOException e) {
  165. e.printStackTrace();
  166. }
  167. PdfGState gs = new PdfGState();
  168. //添加透明度
  169. gs.setFillOpacity(0.4f);
  170. PdfContentByte content = writer.getDirectContentUnder();
  171. content.beginText();
  172. //水印颜色
  173. content.setColorFill(BaseColor.DARK_GRAY);
  174. content.setGState(gs);
  175. //水印字体样式和大小
  176. content.setFontAndSize(font, 35);
  177. //插入水印 循环每页插入的条数
  178. for (int j = 0; j < 3; j++) {
  179. content.showTextAligned(Element.ALIGN_CENTER, "锦鲤飞上天测试水印", 300, 200 * (j + 1), 30);
  180. }
  181. content.endText();
  182. }
  183. /**
  184. *
  185. * TODO 关闭文档时,替换模板,完成整个页眉页脚组件
  186. *
  187. * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter,
  188. * com.itextpdf.text.Document)
  189. */
  190. public void onCloseDocument(PdfWriter writer, Document document) {
  191. // 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
  192. total.beginText();
  193. total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
  194. String foot2 = " " + (writer.getPageNumber()) + " 页"; //页脚内容拼接 如 第1页/共2页
  195. // String foot2 = String.valueOf(writer.getPageNumber()); //页脚内容拼接 如 1/2
  196. total.showText(foot2);// 模版显示的内容
  197. total.endText();
  198. total.closePath();
  199. }
  200. }

四、生成pdf,多页模板方式

2023-03-27更新,各位粉丝本人在用过一段时间pdf生成以后,突然有了多页模板图片和描述的需求,需要多页画模板域,因此呢有了下面的代码。

  1. import cn.hutool.core.date.DateUtil;
  2. import com.example.demo.domain.DuizhangDomain;
  3. import com.example.demo.domain.YqTable;
  4. import com.example.demo.pdf.phantom.App;
  5. import com.example.demo.pdf.phantom.PageEvent;
  6. import com.itextpdf.text.*;
  7. import com.itextpdf.text.pdf.*;
  8. import freemarker.template.TemplateException;
  9. import org.springframework.core.io.ClassPathResource;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.ByteArrayOutputStream;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.io.OutputStream;
  15. import java.math.BigDecimal;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * 根据模板填充数据及图片,动态生成数据列表
  20. */
  21. public class CreatePdfEchrtsAndTableMain2 {
  22. private final static String TITLE = "这个是标题,可有可无";
  23. public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {
  24. //设置请求返回类型
  25. response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");
  26. OutputStream outputStream = response.getOutputStream();
  27. //模板路径,放到项目里用这个ClassPathResource
  28. ClassPathResource classPathResource = new ClassPathResource("templates/test1.pdf");
  29. InputStream inputStream = classPathResource.getInputStream();
  30. PdfReader reader = new PdfReader(inputStream);
  31. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  32. PdfStamper ps = new PdfStamper(reader, bos);
  33. //设置字体
  34. final BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  35. ArrayList<BaseFont> fontList = new ArrayList<>();
  36. fontList.add(font);
  37. //提取表单,这个是模板画好的文本框
  38. AcroFields s = ps.getAcroFields();
  39. s.setSubstitutionFonts(fontList);
  40. //这里需要注意一下,多模块的时候文本域是可以随便填写的,但是图片的文本域需要获取下一页的坐标。
  41. s.setFieldProperty("jrfk","textfont",font,null);
  42. s.setFieldProperty("bjzs","textfont",font,null);
  43. s.setFieldProperty("type","textfont",font,null);
  44. s.setFieldProperty("createTime","textfont",font,null);
  45. s.setFieldProperty("title","textfont",font,null);
  46. s.setField("jrfk","10");
  47. s.setField("bjzs","20");
  48. s.setField("type","日报");
  49. s.setField("createTime", DateUtil.now());
  50. s.setField("title", TITLE);
  51. //添加图片,这是获取的第一页的PdfContentByte
  52. PdfContentByte cb = ps.getOverContent(1);
  53. //添加logo
  54. Rectangle logo = s.getFieldPositions("logo").get(0).position;
  55. Image logoImage = Image.getInstance("https://img1.baidu.com/it/u=3646261857,3326755268&fm=253&app=138&size=w931&n=0&f=JPG&fmt=auto?sec=1668186000&t=20050fc88fc3feb1f9d28392f4595ec6");
  56. //根据域的大小缩放图片,我这里宽度在原有的域基础上加了100,你们可以自己调节
  57. logoImage.scaleToFit(logo.getWidth() + 100,logo.getHeight());
  58. logoImage.setAlignment(Image.MIDDLE);
  59. logoImage.setAbsolutePosition(logo.getLeft(),logo.getBottom());
  60. cb.addImage(logoImage);
  61. //获取统计图
  62. //获取域
  63. Rectangle rlt = s.getFieldPositions("rlt").get(0).position;
  64. //热力图
  65. Image rltImage = Image.getInstance("https://img0.baidu.com/it/u=4043177345,1055141017&fm=253&app=138&size=w931&n=0&f=PNG&fmt=auto?sec=1668186000&t=8cfdc5c95cc0070eb91946d780ee8dc3");
  66. //根据域大小设置缩放图片
  67. rltImage.scaleToFit(rlt.getWidth() + 100,rlt.getHeight());
  68. // 设置居中
  69. rltImage.setAlignment(Image.MIDDLE);
  70. //绝对定位
  71. rltImage.setAbsolutePosition(rlt.getLeft(),rlt.getBottom());
  72. //图片旋转,这个可以将图片进行一个旋转,看自己需求
  73. // rltImage.setRotationDegrees(90);
  74. cb.addImage(rltImage);
  75. //按机构统计图
  76. //这个是生成echarts的类,如果需要生成echarts可以去看我的另一个文章,上面前言已经提到了
  77. App app1 = new App();
  78. byte[] echarts1 = app1.createEcharts("ajg.ftl");
  79. Image ajgImage = Image.getInstance(echarts1);
  80. Rectangle ajg = s.getFieldPositions("ajg").get(0).position;
  81. // 根据域大小设置缩放图片
  82. ajgImage.scaleToFit(ajg.getWidth(),400);
  83. // 设置居中
  84. ajgImage.setAlignment(Image.MIDDLE);
  85. // 绝对定位
  86. ajgImage.setAbsolutePosition(ajg.getLeft(),ajg.getBottom());
  87. cb.addImage(ajgImage);
  88. //按机构排名,这个是在图片的基础上还要添加数据,这个模板可以画好
  89. for (int i = 1; i <= 3; i++) {
  90. s.setFieldProperty("ajg" + i,"textfont",font,null);
  91. s.setField("ajg" + i,"机构" + i);
  92. }
  93. App app = new App();
  94. byte[] echarts = app.createEcharts("option.ftl");
  95. //按业务
  96. Rectangle ayw = s.getFieldPositions("ayw").get(0).position;
  97. Image aywImage = Image.getInstance(echarts);
  98. // 设根据域大小设置缩放图片
  99. aywImage.scaleToFit(ayw.getWidth(), 400);
  100. // 设置居中
  101. aywImage.setAlignment(Image.MIDDLE);
  102. // 绝对定位
  103. aywImage.setAbsolutePosition(ayw.getLeft(),ayw.getBottom());
  104. cb.addImage(aywImage);
  105. //按业务排名
  106. for (int i = 1; i <= 3; i++) {
  107. s.setFieldProperty("ayw" + i,"textfont",font,null);
  108. s.setField("ayw" + i,"机构" + i);
  109. }
  110. //按场合
  111. Rectangle acj = s.getFieldPositions("acj").get(0).position;
  112. Image acjImage = Image.getInstance(echarts);
  113. // 设根据域大小设置缩放图片
  114. acjImage.scaleToFit(acj.getWidth(), 400);
  115. // 设置居中
  116. acjImage.setAlignment(Image.MIDDLE);
  117. // 绝对定位
  118. acjImage.setAbsolutePosition(acj.getLeft(),acj.getBottom());
  119. cb.addImage(acjImage);
  120. //按场景排名
  121. for (int i = 1; i <= 3; i++) {
  122. s.setFieldProperty("acj" + i,"textfont",font,null);
  123. s.setField("acj" + i,"机构" + i);
  124. }
  125. //按等级
  126. Rectangle adj = s.getFieldPositions("adj").get(0).position;
  127. Image adjImage = Image.getInstance(echarts);
  128. // 设根据域大小设置缩放图片
  129. adjImage.scaleToFit(adj.getWidth(),400);
  130. // 设置居中
  131. adjImage.setAlignment(Image.MIDDLE);
  132. // 绝对定位
  133. adjImage.setAbsolutePosition(adj.getLeft(),adj.getBottom());
  134. cb.addImage(adjImage);
  135. //按场景排名
  136. for (int i = 1; i <= 3; i++) {
  137. s.setFieldProperty("adj" + i,"textfont",font,null);
  138. s.setField("adj" + i,"机构" + i);
  139. }
  140. //第二页的图片域,如果第三页有模板写3即可
  141. PdfContentByte cb2 = ps.getOverContent(2);
  142. //添加图片
  143. Rectangle test = s.getFieldPositions("test").get(0).position;
  144. byte[] base = bankReportPdfService.getBankHistogramDataBase64All(bankId, startTime, endTime, reportTimeType, bank);
  145. Image testImage = Image.getInstance(base);
  146. //这里需要注意一下,如果没有获取第二页的PdfContentByte的话直接填充第二页的图片域图片会顶上去
  147. // 设根据域大小设置缩放图片
  148. testImage .scaleToFit(test .getWidth(),400);
  149. // 设置居中
  150. testImage .setAlignment(Image.MIDDLE);
  151. // 绝对定位
  152. testImage .setAbsolutePosition(test .getLeft(),test .getBottom());
  153. cb2.ddImage(testImage );
  154. ps.setFormFlattening(true);
  155. ps.close();
  156. //*******************填充编辑好后的pdf**************
  157. reader = new PdfReader(bos.toByteArray());
  158. Rectangle pageSize = reader.getPageSize(1);
  159. Document document = new Document(pageSize);
  160. PdfWriter writer = PdfWriter.getInstance(document, outputStream);
  161. writer.setPageEvent(new PageEvent());
  162. // 打开文档
  163. document.open();
  164. PdfContentByte cbUnder = writer.getDirectContentUnder();
  165. //多页模板,你有几页模板写几页就行,我这是两页模板
  166. for (int i = 1; i <= 2; i++) {
  167. PdfImportedPage pageTemplate = writer.getImportedPage(reader, i);
  168. cbUnder.addTemplate(pageTemplate, 0, 0);
  169. //这里每次循环都要创建一个新的页
  170. document.newPage();
  171. }
  172. createTable(writer,document);
  173. // document.newPage();
  174. createTableYq(writer,document);
  175. document.close();
  176. outputStream.close();
  177. }
  178. //为一个表格添加内容
  179. public PdfPCell createSetCell(String value,Font font){
  180. PdfPCell cell = new PdfPCell();
  181. cell.setPhrase(new Phrase(value,font));
  182. cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  183. cell.setHorizontalAlignment(Element.ALIGN_CENTER);
  184. return cell;
  185. }
  186. //添加表格
  187. public void createTable(PdfWriter writer,Document document) throws DocumentException, IOException {
  188. PdfPTable table = new PdfPTable(new float[] {
  189. 30, 80, 50, 50, 50});
  190. table.setTotalWidth(520);
  191. table.setPaddingTop(500);
  192. table.setLockedWidth(true);
  193. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  194. table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());
  195. //每页都显示表头,输入几就是第几行的表头固定
  196. table.setHeaderRows(2);
  197. table.setHeaderRows(3);
  198. //定义数据的字体
  199. BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
  200. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  201. PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
  202. cell.setHorizontalAlignment( Element.ALIGN_LEFT);
  203. cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
  204. cell.setBorder(Rectangle.NO_BORDER);
  205. cell.setColspan(5);
  206. table.addCell(cell);
  207. //表头信息
  208. PdfPCell heandCell = new PdfPCell();
  209. heandCell.setRowspan(1);
  210. heandCell.setColspan(5);
  211. heandCell.setFixedHeight(60);
  212. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  213. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  214. heandCell.setPhrase(new Phrase(TITLE + "对账情况表",textFont));
  215. table.addCell(heandCell);
  216. //表字段
  217. String title[] = {
  218. "序号","机构","已对账","未对账","对账率%"};
  219. for (int i = 0; i < title.length; i++) {
  220. PdfPCell heardCell = new PdfPCell();
  221. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  222. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  223. heardCell.setPhrase(new Phrase(title[i], textFont));
  224. heardCell.setMinimumHeight(20);
  225. table.addCell(heardCell);
  226. }
  227. //列表数据
  228. List<DuizhangDomain> duizhangDomains = new ArrayList<>();
  229. for (int i = 1; i <= 1000; i++) {
  230. DuizhangDomain duizhangDomain = new DuizhangDomain();
  231. duizhangDomain.setJg("机构" + i).setYdz(i).setWdz(i).setDzl(new BigDecimal(i));
  232. duizhangDomains.add(duizhangDomain);
  233. }
  234. for (int i = 0; i < duizhangDomains.size(); i++) {
  235. PdfPCell setCell1 = createSetCell((i + 1) + "", textFont);
  236. PdfPCell setCell2 = createSetCell(duizhangDomains.get(i).getJg(), textFont);
  237. PdfPCell setCell3 = createSetCell(duizhangDomains.get(i).getYdz().toString(), textFont);
  238. PdfPCell setCell4 = createSetCell(duizhangDomains.get(i).getWdz().toString(), textFont);
  239. PdfPCell setCell5 = createSetCell(duizhangDomains.get(i).getDzl() + "%", textFont);
  240. table.addCell(setCell1);
  241. table.addCell(setCell2);
  242. table.addCell(setCell3);
  243. table.addCell(setCell4);
  244. table.addCell(setCell5);
  245. }
  246. document.add(table);
  247. }
  248. public void createTableYq(PdfWriter writer,Document document) throws DocumentException, IOException {
  249. PdfPTable table = new PdfPTable(new float[] {
  250. 80, 50});
  251. table.setTotalWidth(520);
  252. table.setPaddingTop(500);
  253. table.setLockedWidth(true);
  254. table.setHorizontalAlignment(Element.ALIGN_CENTER);//居中
  255. table.writeSelectedRows(0, -1,500,800,writer.getDirectContentUnder());
  256. //每页都显示表头,输入几就是第几行的表头固定
  257. table.setHeaderRows(2);
  258. table.setHeaderRows(3);
  259. //定义数据的字体
  260. BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
  261. Font textFont = new Font(baseFont, 10, Font.NORMAL);
  262. //这个是为了区分两个表格加的一个间隔,可以去掉
  263. PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
  264. cell.setHorizontalAlignment( Element.ALIGN_LEFT);
  265. cell.setVerticalAlignment(Element.ALIGN_BOTTOM);
  266. cell.setBorder(Rectangle.NO_BORDER);
  267. cell.setColspan(2);
  268. table.addCell(cell);
  269. //表头信息
  270. PdfPCell heandCell = new PdfPCell();
  271. heandCell.setRowspan(1);
  272. heandCell.setColspan(2);
  273. heandCell.setFixedHeight(60);
  274. heandCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  275. heandCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  276. heandCell.setPhrase(new Phrase(TITLE + "逾期表",textFont));
  277. table.addCell(heandCell);
  278. //表字段
  279. String title[] = {
  280. "机构名称","逾期数"};
  281. for (int i = 0; i < title.length; i++) {
  282. PdfPCell heardCell = new PdfPCell();
  283. heardCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
  284. heardCell.setHorizontalAlignment(Element.ALIGN_CENTER);
  285. heardCell.setPhrase(new Phrase(title[i], textFont));
  286. heardCell.setMinimumHeight(20);
  287. table.addCell(heardCell);
  288. }
  289. //列表数据
  290. List<YqTable> yqTables = new ArrayList<>();
  291. for (int i = 1; i <= 1000; i++) {
  292. YqTable yq = new YqTable();
  293. yq.setJg("逾期机构" + i).setYqs(i);
  294. yqTables.add(yq);
  295. }
  296. for (int i = 0; i < yqTables.size(); i++) {
  297. PdfPCell setCell2 = createSetCell(yqTables.get(i).getJg(), textFont);
  298. PdfPCell setCell3 = createSetCell(yqTables.get(i).getYqs().toString(), textFont);
  299. table.addCell(setCell2);
  300. table.addCell(setCell3);
  301. }
  302. document.add(table);
  303. }
  304. }

生成结果示例
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到第二页我也是通过模板的图片文本域生成图片,我们可以通过这种方法来进行多页模板生成。

五、图片加入pdf动态生成,不需要添加指定模板域

2023-06-30更新,今天有朋友问图片能不能动态渲染位置,不需要添加模板域,其实是可以的,我把代码粘贴到下面,大家可以做个参考,其实看到这里基本上套路大家也就知道了,所以我就不粘贴那些繁琐的创建pdf的document之类的代码了,直接上面粘贴就行,这里只粘贴关于无指定域添加图片的代码。

  1. //获取图片的字节码,这里我是用echarts生成的统计图,如果对echarts后台生成感兴趣的话可以看我另一篇文章(文章是收费的哦,白嫖客不用点了)。
  2. byte[] base = bankReportPdfService.getBankHistogramDataBase64All(bankId, startTime, endTime, reportTimeType, bank);
  3. Image ajgAllImage = Image.getInstance(base);
  4. //设置图片位置的x轴和y轴
  5. ajgAllImage.setAbsolutePosition(80, 400);//注意是从文档的左下角往右、往上计算的
  6. //设置图片的宽度和高度
  7. ajgAllImage.scaleToFit(1000, 300);
  8. // 设置居中
  9. ajgAllImage.setAlignment(Image.MIDDLE);
  10. //将图片添加到pdf文件中
  11. document.add(ajgAllImage);

只需要这一段代码就可以实现动态添加无模块域图片了,如果需要好多页面添加的话就加上document.newPage();,重新new一页,就可以了,注意间距,每页的xy轴都是从0开始的。

好了这就是生成pdf的代码了,controller层我就不粘出来了自己搞一下吧,希望可以帮助各位有需要的人,如果帮助到你了就帮忙点个赞,关注一下,我会不定时更新一些自己解决过的业务,希望可以帮助大家!!!

发表评论

表情:
评论列表 (有 0 条评论,140人围观)

还没有评论,来说两句吧...

相关阅读