这篇文章比较长,包括三个模块的内容:
- 用到的相关jar包及其版本号
- 根据velocity模板生成html文件方法
- 根据html文件生成pdf文件方法
如果你是其它方法已经生成了html模板,则直接参考3即可。
文章中需要用到的jar包及代码文件下载地址:Jar包及素材下载
如果你实在是懒,我这里还有一个java项目,导入eclipse即可执行。懒人直接下载项目,记得点赞哈
1:相关jar包及其版本号
flying-saucer-pdf-itext5-9.1.13
flying-saucer-core-9.1.13
itextpdf-5.5.11
xmlworker-5.5.11
itext-asian-5.2.0
<!--iText对PDF做数字证书时用到的第三方加密解密工具包-->
bcpkix-jdk15on-1.58
bcprov-jdk15on-1.58
<!--读取velocity模板内容jar包 -->
jodd-core-3.7.1
maven依赖:
<!--html转pdf,签章-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.11</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.1.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-core -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-core</artifactId>
<version>9.1.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!--iText对PDF做数字证书时用到的第三方加密解密工具包-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.58</version>
</dependency>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-core</artifactId>
<version>3.7.1</version>
</dependency>
2:根据velocity模板生成html文件方法
核心代码;
import jodd.io.FileUtil; //fileUtil所在jar包
//1:获取合同模板内容
/**
* 获取合同模板内容
* @param templateName 模板路径
* @return
*/
public String getOrderContractTemplateContent(String contractFileUrl) {
File contractFile = new File(contractFileUrl);
/*
合同模板不存在
*/
if (!contractFile.exists()) {
// 判断父文件夹是否存在
File destFile = contractFile.getParentFile();
if (!destFile.exists() && !destFile.isDirectory()) {
destFile.mkdirs();
}
LOGGER.error(String.format("合同模板:%s 不存在,路径地址:%s,请及时上传!", templateName, orderContractFileUrl));
return null;
}
try {
return FileUtil.readString(contractFile);
} catch (IOException e) {
LOGGER.error(String.format("获取合同模板:%s 异常!", templateName), e);
}
}
//2:替换模板内容中的变量,templateDO是封装模板中变量的实体类,根据你的业务构建,传入即可
String vmContent = getOrderContractTemplateContent("模板文件路径地址");
Map<String, Object> dataMap = new HashedMap();
dataMap.put("orderTemplate", templateDO);
String htmlContent = VelocityUtil.parseString(vmContent, dataMap, "");
String htmlFileName = String.format("%s/%s.html", path, fileName); //生成html文件路径+名称
File htmlFile = new File(htmlFileName);
return generateNewHtml(htmlFile, htmlContent);
/**
* 保存替换变量后的模板为html文件 保存到磁盘
* @param newFile 生成html文件
* @param html 替换变量后的模板文件内容
* @return
*/
private String generateNewHtml(File newFile, String html) {
if (newFile == null) {
LOGGER.error("生成新html文件路径不能为空!");
return null;
}
if (StringUtil.isNullorEmpty(html)) {
LOGGER.error("替换模板中变量后,文件内容为空!");
return null;
}
OutputStream out = null;
InputStream in = null;
OutputStreamWriter oStreamWriter = null;
InputStreamReader inputStreamReader = null;
try {
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
if (!newFile.exists()) {
newFile.createNewFile();
}
//读写操作
out = new FileOutputStream(newFile);
in = new ByteArrayInputStream(html.getBytes());
inputStreamReader = new InputStreamReader(in);
oStreamWriter = new OutputStreamWriter(out, "UTF-8");
//创建字符流缓冲区
BufferedReader buffer = new BufferedReader(inputStreamReader);//缓冲
String line;
while ((line = buffer.readLine()) != null) {
oStreamWriter.append(line);
}
oStreamWriter.flush();
return newFile.getPath();
} catch (Exception ex) {
LOGGER.error("保存文件失败generateNewHtml", ex);
return null;
} finally {
//放回资源
try {
if (in != null) {
in.close();
}
if (oStreamWriter != null) {
oStreamWriter.close();
}
if (out != null) {
out.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
} catch (Exception ignored) {
LOGGER.error("关闭流资源时异常,流关闭失败!", ignored);
}
}
}
3:根据html文件生成pdf文件方法
import com.itextpdf.text.pdf.BaseFont;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* 根据html文件生成pdf文件
* @param htmlPath html文件路径
* @param pdfPath 生成的pdf路径
* @return
*/
public static boolean generatePdf(String htmlPath,String pdfPath) {
OutputStream output = null;
try {
output = new FileOutputStream(pdfPath);
//实例ITextRenderer,加载html文档
ITextRenderer renderer = new ITextRenderer();
//添加字体,以支持中文
renderer.getFontResolver().addFont( "G:\\a\\soft\\Fonts\\Nsimsun.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
String url = new File(htmlPath).toURI().toURL().toString(); //关键 不写这一句,中文字体出不来
renderer.setDocument(url);
//嵌入图片磁盘目录
renderer.getSharedContext().setBaseURL("file:/G:/a/static/template/");
renderer.layout();
renderer.createPDF(output);
output.close();
return true;
} catch (Exception e) {
e.printStackTrace();
if (output != null) {
try {
output.close();
} catch (IOException e1) {
e1.printStackTrace();
LOGGER.error("HtmlToPdfUtilForCss--->生成pdf输出流关闭失败!",e1);
}
}
return false;
}
}
上面代码设置加载的字体为Nsimsun.TFF(新宋体),在html中一定要指定全文字体为新宋体,要不生成的pdf文件中文不显示。
注意事项:
(1):html生成pdf时,不支持一些特殊的html语法标签,比如:
所以需要在读取内容转html时,需把" " 替换掉。可以替换为""或替换成 "
 "
 是xml文件格式中的空格符号。
(2):html文件转pdf文件时,加载的字体嵌入性一定要是“可编辑”以上权限的,要不会报错。
文章中需要用到的jar包及