本次使用的是itext pdf5(PDF填充:文本框,图片
参考博客:博客1)
推荐使用itext pdf7 (参考博客:https://blog.youkuaiyun.com/u012397189/category_6356371.html)
一、制作PDF模板
开始编辑:
先下载万兴PDF编辑器(Wondershare PDFelement Professional 7)破解版
链接:https://pan.baidu.com/s/1eKj0ZErexAwTWrHT9wvG3A
提取码:jce4
1.先编辑好word,转为PDF作为模板
2.用此编辑器打开PDF模板
3.选择“表单” > 表单自动识别 > 表单编辑
4.可添加表单
5.修改表单的key值为我们对象中的属性值(对应name,age等,方便填充)
6.保存PDF模板(模板放到项目中也可以读取。我的是上传到了OSS服务器上,用一个url访问PDF模板)
二、Maven依赖:
<!-- itextpdf5 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- hutool工具 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.5</version>
</dependency>
三、代码:
// pdf模板文件路径(oss) 被填充的PDF
private final String TEMPLATE_URL = "http://aliyuncs.com/upload/10b3cfc17869a1e55df64c48f7f.pdf";
/**
* 下载PDF
*
* @param vo 请求查询参数
* @return String 生成PDF链接
*/
@GetMapping("/pdf")
public void downloadPdf(String phone, HttpServletResponse response) {
// 查询要插入的数据 只取最新的那条数据
Optional<LowVoltageResidentElec> voltageOptional = new LambdaQueryChainWrapper<>(lowVoltageResidentElecMapper)
.eq(LowVoltageResidentElec::getIsDeleted, BladeConstant.DB_NOT_DELETED)
.eq(LowVoltageResidentElec::getClientMobilePhone, phone)
.list()
.stream()
.max((s1, s2) -> (int) (s1.getUpdateTime().getTime() - s2.getUpdateTime().getTime()));
if (voltageOptional.isPresent()) {
LowVoltageResidentElec lowVoltageResidentElec = voltageOptional.get();
Map<String, Object> data = BeanUtil.beanToMap(lowVoltageResidentElec);
// 输出pdf文件路径
String targetPath = "";
// 设置windows或linux系统文件上传路径
String fileName = IdUtil.simpleUUID() + ".pdf";
if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
log.info("Windows系统...");
targetPath = customFileConfig.getWindows() + fileName; // d:/测试.pdf
} else {
log.info("Linux系统...");
targetPath = customFileConfig.getLinux() + fileName; // /home/mzp/sg-yc-pj/tmp/测试.pdf
}
BaseFont baseFont = null;
try {
// 字体:宋体
baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
throw new RuntimeException("本地字体读取有误!");
}
PdfReader pdfReader = null;
PdfStamper pdfStamper = null;
try {
URL url = new URL(TEMPLATE_URL);
pdfReader = new PdfReader(url);
pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(targetPath));
} catch (Exception e) {
throw new RuntimeException("模板读取有误!");
}
AcroFields form = pdfStamper.getAcroFields();
form.addSubstitutionFont(baseFont);
// 写入数据 用电信息
try {
form.setField("clientName", data.get("clientName").toString());
form.setField("clientIdCard", data.get("clientIdCard").toString());
form.setField("clientElecAddress", data.get("clientElecAddress").toString());
} catch (Exception e) {
throw new RuntimeException("写入数据有误!");
}
// 服务评价信息 一个业务员对应一个客户
Optional<ServiceEvaluation> evaluationOptional = new LambdaQueryChainWrapper<>(serviceEvaluationMapper)
.eq(ServiceEvaluation::getIsDeleted, BladeConstant.DB_NOT_DELETED)
.eq(ServiceEvaluation::getEvaluationMobile, phone)
.list()
.stream()
.max((s1, s2) -> (int) (s1.getUpdateTime().getTime() - s2.getUpdateTime().getTime()));
ServiceEvaluation serviceEvaluation = null;
if (evaluationOptional.isPresent()) {
serviceEvaluation = evaluationOptional.get();
serviceEvaluation.setPicLink(vo.getPicUrl());
serviceEvaluationService.updateById(serviceEvaluation);
// 添加图片1 手签图片
int pageNo = form.getFieldPositions("manuallySignedUrl1").get(0).page;
Rectangle signRect = form.getFieldPositions("manuallySignedUrl1").get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
// 添加图片2 手签图片
int pageNo2 = form.getFieldPositions("manuallySignedUrl2").get(0).page;
Rectangle signRect2 = form.getFieldPositions("manuallySignedUrl2").get(0).position;
float x2 = signRect2.getLeft();
float y2 = signRect2.getBottom();
Image image = null;
Image image2 = null;
try {
// 写入图片1
image = Image.getInstance(serviceEvaluation.getManuallySignedUrl());
PdfContentByte under = pdfStamper.getOverContent(pageNo);
// 设置图片大小
image.scaleAbsolute(signRect.getWidth(), signRect.getHeight());
// 设置图片位置
image.setAbsolutePosition(x, y);
under.addImage(image);
// 写入图片2
image2 = Image.getInstance(serviceEvaluation.getManuallySignedUrl());
PdfContentByte under2 = pdfStamper.getOverContent(pageNo2);
// 设置图片大小
image2.scaleAbsolute(signRect2.getWidth(), signRect2.getHeight());
// 设置图片位置
image2.setAbsolutePosition(x2, y2);
under2.addImage(image2);
} catch (Exception e) {
throw new RuntimeException("写入手签图片有误!");
}
} else {
log.info("手签图片未写入PDF");
}
//设置不可编辑, pdfStamper.close()后PDF生成
pdfStamper.setFormFlattening(true);
try {
pdfStamper.close();
} catch (Exception e) {
throw new RuntimeException("PDF对象关闭有误!");
}
}
四、效果:
和普通PDF一样。
谷歌浏览器打开字体有问题,需要用wps打开就好了。