itext 根据模板 生成pdf 多行数据
程序员文章站
2022-07-10 18:54:32
前言:基于 html + ccs + itext + 字符串替换完成的。简单,依赖的 jar 少...根据 pdf模板 生成 pdf ,1. 不能有循环的数据(可能有,但我并没有找到);2. table 中的文字无法自适应(可能有,但我并没有找到)。废话完毕了, 先看预览效果吧。红框中的内容,就是 list 数据,长度不固定,无法用 PDF 模板生成。下面是代码:pom.xml文件
前言:基于 html + ccs + itext + 字符串替换完成的。简单,依赖的 jar 少...
根据 pdf模板 生成 pdf ,
1. 不能有循环的数据(可能有,但我并没有找到);
2. table 中的文字无法自适应(可能有,但我并没有找到)。
废话完毕了, 先看预览效果吧。
红框中的内容,就是 list 数据,长度不固定,无法用 PDF 模板生成。
下面是代码:
pom.xml文件
<!--iTextpdf 相关依赖 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.6</version>
</dependency>
java 文件
package org.duzq;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import java.io.*;
import java.nio.charset.Charset;
/**
* 关于这里的异常及文件流
* 1. 异常: 根据自身的业务,补货处理一下;
* 2. 流:一定要在 [ try - catch - finally ] finally 中关闭流,不然啥时候出现 OOM 的时候,你明白的...
* @author duzq
* @date 2020-7-26 16:44:54
*/
public class HtmlPdf {
private static final String DEST = "target/HelloWorld_CN_HTML.pdf";
private static final String HTML = "src/main/resources/template.html";
private static final String HTML_TEMP = "src/main/resources/templateTemp.html";
private static final String FONT = "src/main/resources/simhei.ttf";
public static void main(String[] args) throws IOException, DocumentException {
// 1. 读取html文件
FileInputStream fileInputStream = new FileInputStream(HTML);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream,"utf8"));
String line = null;
while((line = bufferedReader.readLine()) != null) {
// 文字换行显示 stringBuilder.append(System.getProperty("line.separator"));
stringBuilder.append(line);
}
System.out.println(stringBuilder.toString());
// 2. 替换html中的关键字
String htmlStr = stringBuilder.toString();
htmlStr = htmlStr.replaceAll("#bankName#", "邯郸银行人民路支行");
htmlStr = htmlStr.replaceAll("#bankNo#", "111111111111111111111");
htmlStr = htmlStr.replaceAll("#periodCode#", "20200202");
htmlStr = htmlStr.replaceAll("#number1#", "1");
htmlStr = htmlStr.replaceAll("#money1#", "1.00");
htmlStr = htmlStr.replaceAll("#number2#", "2");
htmlStr = htmlStr.replaceAll("#money2#", "2.00");
htmlStr = htmlStr.replaceAll("#number3#", "3");
htmlStr = htmlStr.replaceAll("#money3#", "3.00");
htmlStr = htmlStr.replaceAll("#number4#", "4");
htmlStr = htmlStr.replaceAll("#money4#", "4.00");
htmlStr = htmlStr.replaceAll("#moneyCount1#", "100.00");
htmlStr = htmlStr.replaceAll("#moneyCount2#", "200.00");
htmlStr = htmlStr.replaceAll("#companyName#", "邯郸某个公司");
htmlStr = htmlStr.replaceAll("#auditUser#", "姜瑞珍");
htmlStr = htmlStr.replaceAll("#cashierName#", "杜志强");
htmlStr = htmlStr.replaceAll("#createDate#", "2020-07-26 16:16:50");
// 3. 可以替换成list中的数据, 后续将生成的html格式的字符串,加入到上面读取到的字符串中
String trList = "\n" +
" <tr>\n" +
" <td class='fc'>1</td>" +
" <td class='fc'>收入</td>" +
" <td class='fc'>1</td>" +
" <td class='fl'>资金收入</td>" +
" <td class='fr'>100.00</td>" +
" <td class='fc'></td>" +
" <td class='fc'></td>" +
" <td class='fc'></td>" +
" <td class='fl'></td>" +
" <td class='fr'></td>" +
" </tr>";
trList += "\n" +
" <tr>\n" +
" <td class='fc'>2</td>" +
" <td class='fc'>转出</td>" +
" <td class='fc'>2</td>" +
" <td class='fl'>资金转出</td>" +
" <td class='fr'>200.00</td>" +
" <td class='fc'></td>" +
" <td class='fc'></td>" +
" <td class='fc'></td>" +
" <td class='fl'></td>" +
" <td class='fr'></td>" +
" </tr>";
// 4. 将list中的数据替换到html中
htmlStr = htmlStr.replaceAll("#trList#", trList);
// 5. 生成临时文件 [PS: 文件名称是固定的,当碰到并发时,会出现问题,可以将html文件名称替换成 UUID]
File file = new File(HTML_TEMP);
FileOutputStream fop = new FileOutputStream(file);
if (!file.exists()) {
file.createNewFile();
}
byte[] contentInBytes = htmlStr.getBytes();
fop.write(contentInBytes);
fop.flush();
fop.close();
// 6. 开始生成pdf
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
document.open();
// 插入图片 , 具体怎么用,没有去琢磨...本次需求不涉及图片操作...
// 想法: 在上面的步骤,文件主题已经完成,在最后部分,通过 itext 的 api,将图片放到 pdf文件流中
// 将图片转换成 baset64 字符串的方式,试过了,不好用,才有了当前的这个想法,图片试过了,可以用。
// Image img = Image.getInstance(LOGO_PATH);
// img.setTop(100);
// img.setLeft(50);
// img.setAbsolutePosition(100,100);
// document.add(img);
// 7. 根据 html 模板转换成pdf文件
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontImp.register(FONT);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new FileInputStream(HTML_TEMP), null, Charset.forName("UTF-8"), fontImp);
document.close();
}
}
html 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
<style>
body {
font-family: SimHei;
width: 1080px;
margin: 0 auto;
}
table {
width: 99%;
font-size: 10px;
}
.fc {
text-align: center;
}
.fl {
text-align: left;
}
.fr {
text-align: right;
}
.trBorder td {
border-style: none;
}
</style>
</head>
<body>
<h2 style="text-align: center">银行余额调节</h2>
<table border="1" cellspacing="0" style="border-style: none;">
<tr style="margin-top: 10px;" class="trBorder">
<td colspan="2">开户银行:#bankName#</td>
<td colspan="2">账号:#bankNo#</td>
<td colspan="2">日期:#periodCode#</td>
</tr>
<tr>
<td class="fc" style="width: 330px;">项目</td>
<td class="fc" style="width: 50px;">笔数</td>
<td class="fc" style="width: 100px;">金额</td>
<td class="fc" style="width: 185px;">项目</td>
<td class="fc">笔数</td>
<td class="fc">金额</td>
</tr>
<tr>
<td>本单位账面余额</td>
<td></td>
<td class="fr">0</td>
<td>银行对账单余额</td>
<td></td>
<td class="fr">0</td>
</tr>
<tr>
<td>加:1类银行已收,本单位尚未收</td>
<td class="fc">#number1#</td>
<td class="fr">#money1#</td>
<td>加:3类本单位已收,银行尚未收</td>
<td class="fc">#number3#</td>
<td class="fr">#money3#</td>
</tr>
<tr>
<td>加:2类银行已付,本单位尚未付</td>
<td class="fc">#number2#</td>
<td class="fr">#money2#</td>
<td>加:4类本单位已付,银行尚未付</td>
<td class="fc">#number4#</td>
<td class="fr">#money4#</td>
</tr>
<tr>
<td>调节后的存款余额</td>
<td></td>
<td class="fr">#moneyCount1#</td>
<td>调节后的存款余额</td>
<td></td>
<td class="fr">#moneyCount2#</td>
</tr>
</table>
<table style="margin-top: 20px;" border="1" cellspacing="0">
<tr>
<td class="fc" rowspan="2" width="40px;">未达款项种类</td>
<td class="fc" colspan="2" width="80px;">银行凭证</td>
<td class="fc" rowspan="2" width="202px;">摘要</td>
<td class="fc" rowspan="2" width="80px;">金额</td>
<td class="fc" rowspan="2" width="40px;">未达款项种类</td>
<td class="fc" colspan="2" width="80px;">银行凭证</td>
<td class="fc" rowspan="2">摘要</td>
<td class="fc" rowspan="2" width="80px;">金额</td>
</tr>
<tr>
<td class="fc" width="40px;">名称</td>
<td class="fc" width="40px;">号数</td>
<td class="fc" width="40px;">名称</td>
<td class="fc" width="40px;">号数</td>
</tr>
<tr>
<td class="fc">1</td>
<td class="fc">2</td>
<td class="fc">3</td>
<td class="fl">4</td>
<td class="fr">5</td>
<td class="fc">1</td>
<td class="fc">2</td>
<td class="fc">3</td>
<td class="fl">4</td>
<td class="fr">5</td>
</tr>
#trList#
</table>
<table style="margin-top: 20px;" cellspacing="0">
<tr>
<td>单位名称:#companyName#</td>
</tr>
<tr>
<td class="fl" width="40%;"></td>
<td class="fl">审核:#auditUser#</td>
<td class="fl">出纳:#cashierName#</td>
<td class="fl">编制日期:#createDate#</td>
</tr>
</table>
</body>
</html>
https://blog.csdn.net/weixin_44499394/article/details/90206391
https://www.cnblogs.com/yunfeiyang-88/p/10984740.html
感谢以上二位博主,感谢他们的分享,让我想到了这种解决方式。
Demo 代码地址:https://gitee.com/jin_0611/itextPdfTest
本文地址:https://blog.csdn.net/u014176737/article/details/107595479
下一篇: Java基础语法 -- 面向对象