文章目录
- 前言
- 通过pdf模板生成文件
- 一 . 制作模板
- 二、编辑代码实现模板生成pdf文件
- 三、pdf在线预览和文件下载
- 扩展问题
- 遇到的问题
- 1. 更换字体为宋体常规
前言
通过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文件。
@Test
public 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);