文章目录
- 前言
- 通过pdf模板生成文件
- 一 . 制作模板
- 二、编辑代码实现模板生成pdf文件
- 三、pdf在线预览和文件下载
- 扩展问题
- 遇到的问题
- 1. 更换字体为宋体常规
- 2. 下载时中文文件名乱码问题
前言
通过pdf模板生成文件。
支持文本,图片,勾选框。
本章代码已分享至Gitee: https://gitee.com/lengcz/pdfdemo01
通过pdf模板生成文件
一 . 制作模板
-
先使用wps软件制作一个docx文档
-
将文件另存为pdf文件
-
使用pdf编辑器,编辑表单,(例如福昕PDF阅读器、Adobe Acrobat DC)
不同的pdf编辑器使用方式不同,建议自行学习如何使用pdf编辑器编辑表单
- 将修改后的文件保存为template1.pdf文件。
二、编辑代码实现模板生成pdf文件
- 引入依赖
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency>
- 编写pdf工具类和相关工具
package com.it2.pdfdemo01.util;import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;import java.io.*;
import java.util.List;
import java.util.Map;/*** pdf 工具*/
public class PdfUtil {/*** 通过pdf模板输出到流** @param templateFile 模板* @param dataMap input数据* @param picData image图片* @param checkboxMap checkbox勾选框* @param outputStream 输出流*/public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, OutputStream outputStream) {OutputStream os = null;PdfStamper ps = null;PdfReader reader = null;try {reader = new PdfReader(templateFile);ps = new PdfStamper(reader, outputStream);AcroFields form = ps.getAcroFields();BaseFont bf = BaseFont.createFont("Font/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);form.addSubstitutionFont(bf);if (null != dataMap) {for (String key : dataMap.keySet()) {form.setField(key, dataMap.get(key).toString());}}ps.setFormFlattening(true);if (null != checkboxMap) {for (String key : checkboxMap.keySet()) {form.setField(key, checkboxMap.get(key), true);}}PdfStamper stamper = ps;if (null != picData) {picData.forEach((filedName, imgSrc) -> {List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(filedName);for (AcroFields.FieldPosition fieldPosition : fieldPositions) {int pageno = fieldPosition.page;Rectangle signrect = fieldPosition.position;float x = signrect.getLeft();float y = signrect.getBottom();byte[] byteArray = imgSrc;try {Image image = Image.getInstance(byteArray);PdfContentByte under = stamper.getOverContent(pageno);image.scaleToFit(signrect.getWidth(), signrect.getHeight());image.setAbsolutePosition(x, y);under.addImage(image);} catch (BadElementException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (DocumentException e) {e.printStackTrace();}}});}} catch (Exception e) {e.printStackTrace();} finally {try {ps.close();reader.close();} catch (Exception e) {e.printStackTrace();}}}/*** 通过pdf模板输出到文件** @param templateFile 模板* @param dataMap input数据* @param picData image图片* @param checkboxMap checkbox勾选框* @param outputFile 输出流*/public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, File outputFile) throws IOException {FileOutputStream fos = new FileOutputStream(outputFile);try {output(templateFile, dataMap, picData, checkboxMap, fos);} finally {fos.close();}}/*** 通过pdf模板输出到文件** @param templateFile 模板* @param dataMap input数据* @param picData image图片* @param checkboxMap checkbox勾选框* @param filePath 路径* @param fileName 文件名*/public static void output(String templateFile, Map<String, Object> dataMap, Map<String, byte[]> picData, Map<String, String> checkboxMap, String filePath, String fileName) throws IOException {File file = new File(filePath + File.separator + fileName);output(templateFile, dataMap, picData, checkboxMap, file);}}
package com.it2.pdfdemo01.util;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;/*** 图片工具*/
public class ImageUtil {/*** 通过图片路径获取byte数组** @param url 路径* @return*/public static byte[] imageToBytes(String url) {ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();BufferedImage bufferedImage = null;try {bufferedImage = ImageIO.read(new File(url));ImageIO.write(bufferedImage, "jpg", byteOutput);return byteOutput.toByteArray();} catch (IOException e) {e.printStackTrace();} finally {try {if (byteOutput != null)byteOutput.close();} catch (IOException e) {e.printStackTrace();}}return null;}
}
用到的字体文件(幼圆常规,C盘Windows/Fonts目录下
- 测试用例并执行,生成了pdf文件。
@Testpublic void testPdf() throws IOException {String templateFile = "D:\\test3\\template1.pdf";Map<String, Object> dataMap = new HashMap<>();dataMap.put("username", "王小鱼");dataMap.put("age", "11");dataMap.put("address", "深圳市宝安区和林大道");Map<String, byte[]> picMap = new HashMap<>();byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");picMap.put("head", imageToBytes);Map<String, String> checkboxMap = new HashMap<>();checkboxMap.put("apple", "Yes");checkboxMap.put("orange", "Yes");checkboxMap.put("peach", "No");PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, "D:\\test3", "test1.pdf");System.out.println("-------通过模板生成文件结束-------");}
三、pdf在线预览和文件下载
package com.it2.pdfdemo01.controller;import com.it2.pdfdemo01.util.ImageUtil;
import com.it2.pdfdemo01.util.PdfUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/pdftest")
public class MyPdfController {/*** 在线预览pdf** @param request* @param response* @throws IOException*/@GetMapping("/previewPdf")public void previewPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {String templateFile = "D:\\test3\\template1.pdf";Map<String, Object> dataMap = new HashMap<>();dataMap.put("username", "王小鱼");dataMap.put("age", "11");dataMap.put("address", "深圳市宝安区和林大道");Map<String, byte[]> picMap = new HashMap<>();byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");picMap.put("head", imageToBytes);Map<String, String> checkboxMap = new HashMap<>();checkboxMap.put("apple", "Yes");checkboxMap.put("orange", "Yes");checkboxMap.put("peach", "No");response.setCharacterEncoding("utf-8");response.setContentType("application/pdf");String fileName = new String("测试预览pdf文件".getBytes(), "ISO-8859-1");//避免中文乱码response.setHeader("Content-Disposition", "inline;filename=".concat(String.valueOf(fileName) + ".pdf"));PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, response.getOutputStream());}/*** 下载pdf** @param request* @param response* @throws IOException*/@GetMapping("/downloadPdf")public void downloadPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {String templateFile = "D:\\test3\\template1.pdf";Map<String, Object> dataMap = new HashMap<>();dataMap.put("username", "王小鱼");dataMap.put("age", "11");dataMap.put("address", "深圳市宝安区和林大道");Map<String, byte[]> picMap = new HashMap<>();byte[] imageToBytes = ImageUtil.imageToBytes("D:\\test3\\dog3.png");picMap.put("head", imageToBytes);Map<String, String> checkboxMap = new HashMap<>();checkboxMap.put("apple", "Yes");checkboxMap.put("orange", "Yes");checkboxMap.put("peach", "No");response.setCharacterEncoding("utf-8");response.setContentType("application/pdf");String fileName = new String("测试预览pdf文件".getBytes(), "ISO-8859-1");//避免中文乱码response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(fileName) + ".pdf"));PdfUtil.output(templateFile, dataMap, picMap, checkboxMap, response.getOutputStream());}
}
启动服务器测试
- 预览,访问 http://localhost:8080/pdftest/previewPdf
- 下载 访问 http://localhost:8080/pdftest/downloadPdf
预览和下载的区别,只有细微区别。
扩展问题
android手机浏览器不能在线预览pdf文件,pc浏览器和ios浏览器可以在线预览pdf文件。
解决方案请见: https://lengcz.blog.csdn.net/article/details/132604135
遇到的问题
1. 更换字体为宋体常规
只能是下面这种写法
// BaseFont bf = BaseFont.createFont("Font/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //幼圆常规String srcFilePath = PdfUtil.class.getResource("/")+ "Font/simsun.ttc"; //宋体常规String templatePath = srcFilePath.substring("file:/".length())+",0";BaseFont bf = BaseFont.createFont(templatePath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
2. 下载时中文文件名乱码问题
String fileName = new String("测试预览pdf文件".getBytes(), "ISO-8859-1");//避免中文乱码response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(fileName) + ".pdf"));
点击下载