业务描述:后端实现使用PDF模版导出文件。
准备:一个PDF模版,模版内需要填充的字段全部设置为表单。可用Adobe Acrobat DC编辑。
依赖:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
导出步骤:
1、获取模版文件
InputStream inputStream = FileUtils.class.getClassLoader().getResourceAsStream("template/gnkxdbCertification.pdf");
文件放在resources里面,使用ClassLoader获取输入流。
2、创建reader和stamper和AcroFields,最后是关闭
File targetPdf = new File(exportVO.getEShipName() + "_" + param.getIvoyage() + "/" + exportVO.getEShipName() + "_" + param.getIvoyage() + "_" + exportVO.getBl() + i + ".pdf");
PdfReader reader = null;
PdfStamper stamper = null;
try {
reader = new PdfReader(inputStream);
stamper = new PdfStamper(reader, Files.newOutputStream(targetPdf.toPath()));
AcroFields form = stamper.getAcroFields();
// ...
// ...此处为填充模版的部分
// ...
// 关闭填充器和读取器
stamper.setFormFlattening(true);
} finally {
/*关闭stamper*/
if (stamper != null) {
try {
stamper.close();
} catch (Exception e) {
log.error("关闭[stamper]失败", e);
}
}
/*关闭reader*/
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
log.error("关闭[reader]失败", e);
}
}
}
3、填充表单
例子:
form.setField("vename", exportVO.getEShipName());
form.setField("chname", exportVO.getCShipName());
form.setField("imo", exportVO.getShipImo());
form.setField("voyage", param.getIvoyage());
form.setField("lport", exportVO.getLport());
我没找到像word那样填充List的方法,不知道是不是不支持。
4、输出文件
方法中涉及的工具类可用hutool代替。
/**
* 将文件写入请求响应流然后删除该文件
*
* @param file 写入文件
* @param response 请求响应
* @param safeChars 安全字符,编码文件名时忽略这些字符
*/
public static void writeToResponseThenDelete(@Nonnull File file, @Nonnull HttpServletResponse response, char... safeChars) {
response.setContentType("application/octet-stream");
String name = file.getName();
String filename = RFC3986.PATH.encode(name, CharsetUtil.CHARSET_UTF_8, safeChars);
String header = "attachment;filename=" + filename;
log.info("文件名:{},{}编码后的文件名:{}", name, CHARSET, filename);
response.setHeader("Content-Disposition", header);
try (
FileInputStream is = new FileInputStream(file);
ServletOutputStream os = response.getOutputStream()
) {
IOUtils.copy(is, os);
log.info("文件写入请求响应流成功,文件路径:" + file.getAbsolutePath());
os.flush();
} catch (IOException e) {
throw new ServiceException("文件写入请求响应流失败", e);
} finally {
/*无论是否写入响应流,均删除文件*/
if (FileUtil.del(file)) {
log.info("文件删除成功,文件路径:{}", file.getAbsolutePath());
} else {
log.error("文件删除失败,文件路径:{}", file.getAbsolutePath());
}
}
}
5、如果需要合并pdf,请查看 这个