文章目录
- 前言
- 配置
- 1.maven依赖
- 2.PDFUtils
- 使用
- 1.Adobe Acrobat Pro DC
- 2. 测试
- 3. 合并
前言
最近项目需要用到有关PDF的操作,网上查了很多资料,觉得itext7比较符合我的需求,在此做一下简单地记录。
itext7相对于itext5做了很多改动,所以如果使用itext5的话本文并不适用。不过官网有着非常详细的API文档以及演示,具体可以去官网查看。
官网链接
配置
1.maven依赖
我是使用maven引入的,并且是全家桶,因为第一次使用,这样比较方便。
1 2 3 4 5 6 7 | <!-- PDF操作,itext7全家桶 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>7.1.8</version> <type>pom</type> </dependency> |
2.PDFUtils
封装的PDF工具类,导包直接选中itext相关的就好,注意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | public class PDFUtils { /** * 获取默认字体 * * @return */ public static PdfFont getDefaultFont() { try { return PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", true); } catch (IOException e) { // 记录日志 e.printStackTrace(); } return null; } /** * 替换PDF文本表单域变量 * * @param templatePdfPath * 要替换的pdf全路径 * @param params * 替换参数 * @param destPdfPath * 替换后保存的PDF全路径 * * @throws FileNotFoundException * @throws IOException */ public static final void replaceTextFieldPdf(String templatePdfPath, String destPdfPath, Map<String, String> params) throws FileNotFoundException, IOException { PdfDocument pdf = new PdfDocument(new PdfReader(templatePdfPath), new PdfWriter(destPdfPath)); if (params != null && !params.isEmpty()) {// 有参数才替换 PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true); Map<String, PdfFormField> fields = form.getFormFields(); // 获取所有的表单域 for (String param : params.keySet()) { PdfFormField formField = fields.get(param); // 获取某个表单域 if (formField != null) { formField.setFont(getDefaultFont()).setValue(params.get(param)); // 替换值 } } form.flattenFields();// 锁定表单,不让修改 } pdf.close(); } /** * 替换PDF图片表单域(文本)变量,1、获取表单域的大小;2、根据表单域的位置,确定图片的位置;3、如果图片的宽或者高大于表单域,则等比压缩图片。 * * @param templatePdfPath * 要替换的pdf全路径 * @param params * 替换参数 * @param destPdfPath * 替换后保存的PDF全路径 * * @throws FileNotFoundException * @throws IOException */ public static final void replaceImageFieldPdf(String templatePdfPath, String destPdfPath, Map<String, String> params) throws FileNotFoundException, IOException { PdfDocument pdf = new PdfDocument(new PdfReader(templatePdfPath), new PdfWriter(destPdfPath)); if (params != null && !params.isEmpty()) {// 有参数才替换 PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true); Map<String, PdfFormField> fields = form.getFormFields(); // 获取所有的表单域 for (String param : params.keySet()) { PdfFormField formField = fields.get(param); if (formField != null) { replaceFieldImage(params, pdf, param, formField); // 替换图片 } } form.flattenFields();// 锁定表单,不让修改 } pdf.close(); } /** * 替换域中的图片 * * @param params * @param pdf * @param param * @param formField * @throws MalformedURLException */ private static void replaceFieldImage(Map<String, String> params, PdfDocument pdf, String param, PdfFormField formField) throws MalformedURLException { String value = params.get(param); String[] values = value.split("\\|"); Rectangle rectangle = formField.getWidgets().get(0).getRectangle().toRectangle(); // 获取表单域的xy坐标 PdfCanvas canvas = new PdfCanvas(pdf.getPage(Integer.parseInt(values[0]))); ImageData image = ImageDataFactory.create(values[1]); float imageWidth = image.getWidth(); float imageHeight = image.getHeight(); float rectangleWidth = rectangle.getWidth(); float rectangleHeight = rectangle.getHeight(); float tempWidth = 0; float tempHeight = 0; int result = 1; // 压缩宽度 if (imageWidth > rectangleWidth) { tempHeight = imageHeight * rectangleWidth / imageWidth; if (tempHeight > rectangleHeight) { tempHeight = rectangleHeight; result = 2; // 压缩高度 } else { tempWidth = rectangleWidth; tempHeight = imageHeight * rectangleWidth / imageWidth; } } else { if (imageHeight > rectangleHeight) { tempHeight = rectangleHeight; result = 2; } else { result = 3; } } float y = 0; if (result == 1) { // 压缩宽度 y = rectangleHeight - tempHeight; } else if (result == 3) { // 不压缩 y = rectangleHeight - imageHeight; } // y/=2; // 如果想要图片在表单域的上下对齐,这个值除以2就行。同理可以计算x的偏移 if (result == 1) { canvas.addImage(image, rectangle.getX(), rectangle.getY() + y, tempWidth, false); } else if (result == 2) { canvas.addImage(image, rectangle.getX(), rectangle.getY(), tempHeight, false, false); } else if (result == 3) { canvas.addImage(image, rectangle.getX(), rectangle.getY() + y, false); } } /** * 添加水印 * * @throws IOException * @throws FileNotFoundException */ @SuppressWarnings("resource") public static final void addWatermark(String srcPdfPath, String destPdfPath, String watermarkText) throws FileNotFoundException, IOException { PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPdfPath), new PdfWriter(destPdfPath)); pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, new IEventHandler() { @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent) event; PdfDocument pdfDoc = docEvent.getDocument(); PdfPage page = docEvent.getPage(); PdfFont font = null; try { font = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD); // 要显示中文水印的话,需要设置中文字体,这里可以动态判断 } catch (IOException e) { e.printStackTrace(); } PdfCanvas canvas = new PdfCanvas(page); PdfExtGState gs1 = new PdfExtGState(); gs1.setFillOpacity(0.5f); // 水印透明度 canvas.setExtGState(gs1); new Canvas(canvas, pdfDoc, page.getPageSize()).setFontColor(ColorConstants.LIGHT_GRAY).setFontSize(60) .setFont(font).showTextAligned(new Paragraph(watermarkText), 298, 421, pdfDoc.getPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45); } }); pdfDoc.close(); } /** * * @Title: pdfMerger * @Description: PDF合并 * @param paths 需要合并的所有文件路径(路径+名称) * @param outputPath 合并后的文件路径(路径+名称) * void * @author yanghainan * @date 2020年7月3日下午3:21:00 */ public static void pdfMerger(List<String> paths, String outputPath) { if (paths == null || paths.isEmpty() || StringUtils.isBlank(outputPath)) { return; } // 首页与其他页创建方式不同,所以需要两个 PdfDocument pdfDocument = null; PdfDocument pdfDocument2 = null; // 合并工具类 PdfMerger merger = null; try { for (int i = 0; i < paths.size(); i++) { if (i == 0) { pdfDocument = new PdfDocument(new PdfReader(paths.get(i)), new PdfWriter(outputPath)); merger = new PdfMerger(pdfDocument); continue; } pdfDocument2 = new PdfDocument(new PdfReader(paths.get(i))); merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages()); pdfDocument2.close(); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭流 if (pdfDocument != null) { pdfDocument.close(); } if (pdfDocument2 != null) { pdfDocument2.close(); } } } } |
使用
1.Adobe Acrobat Pro DC
使用Adobe Acrobat Pro DC 可以很方便的设置PDF模板,这样我们只需要将数据填充进去就可以了。如果没有安装可以去我的云盘下载:
下载链接
访问码:
如下是项目中用到的一个模板:

光有模板是不够的,还需要对模板进行表单设置:

默认选择就好,成功后会变成这样:

双击字段可以修改属性:

注意这里的名称就是javaBean的属性,需要按照相对应的设置。本文工具类里使用的是Map集合,设置对应的key就好。
2. 测试
1 2 3 4 5 6 7 8 9 10 11 | public static void main(String[] args) throws FileNotFoundException, IOException { String templatePdfPath = "F:\\PDFtemplate\\模板.pdf"; String destPdfPath = "F:\\PDFtemplate\\测试.pdf"; Map<String, String> params = new HashedMap(); params.put("fill_5", "111"); try { PDFUtils.replaceTextFieldPdf(templatePdfPath, destPdfPath, params); } catch (IOException e) { e.printStackTrace(); } } |
运行后:

3. 合并
刚搞好了数据填充生成PDF,又加了个合并PDF的需求,不过好在很简单.
- 官网Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.utils.PdfMerger; import java.io.IOException; public class PdfMerge { private static final String FILE1 = "/uploads/first.pdf"; private static final String FILE2 = "/uploads/second.pdf"; private static final String OUTPUT_FOLDER = "/myfiles/"; public static void main(String args[]) throws IOException { PdfDocument pdfDocument = new PdfDocument(new PdfReader(FILE1), new PdfWriter(OUTPUT_FOLDER + "merged.pdf")); PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(FILE2)); PdfMerger merger = new PdfMerger(pdfDocument); merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages()); pdfDocument2.close(); pdfDocument.close(); } } |
- 我自己写的小Demo
1 2 3 4 5 6 7 8 9 10 11 12 | private static final String FILE1 = "F:\\PDFtemplate\\测试1.pdf"; private static final String FILE2 = "F:\\PDFtemplate\\测试2.pdf"; private static final String FILE3 = "F:\\PDFtemplate\\测试3.pdf"; private static final String OUTPUT_FOLDER = "F:\\PDFtemplate\"; public static void main(String[] args) throws FileNotFoundException, IOException { List<String> paths = new ArrayList<String>(); paths.add(FILE1); paths.add(FILE2); paths.add(FILE3); PDFUtils.pdfMerger(paths, OUTPUT_FOLDER + "测试.pdf"); } |
具体效果就是合并为一个文件,就不再演示了。
本人也是初学,如有错漏欢迎批评指正。