工具类:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
/**
* html转PDF工具类
*
* @author zql
*
*/
public class HtmlToPDF {
private static final Logger logger = Logger.getLogger(HtmlToPDF.class);
/**
* html模板生成PDF文件输出
* 此方法需要maven支持如下:
*
* <dependency>
*
* <groupId>org.xhtmlrenderer</groupId>
*
* <artifactId>core-renderer</artifactId>
*
* <version>R8</version>
*
* </dependency>
*
* @param htmlPath html模板文件路径
* @param map 要替换的字段值
* @param pdfPath pdf输出路径
* @throws Exception
*/
public static void generatePdf(String htmlPath, Map<String, String> map, String pdfPath) throws Exception {
try {
OutputStream outputFile = new FileOutputStream(pdfPath);
// 获取html String形式
String htmlStr = operateHtml(htmlPath, map);
ITextRenderer renderer = new ITextRenderer();
ITextFontResolver font = renderer.getFontResolver();
String sysPath = System.getProperty("user.dir");
String fontPath = sysPath + "\\src\\fonts\\simsun.ttc";
// 添加中文识别,这里是设置的宋体,Linux下要换成对应的字体,中文不显示则给不显示的标签加上样式font-family:'SimSun';
font.addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.setDocumentFromString(htmlStr);
renderer.layout();
renderer.createPDF(outputFile);
renderer.finishPDF();
logger.info("PDF is generate.------------------------------");
} catch (IOException e) {
logger.info("HtmlToPDF.generatePdf occoured IOException! Message:" + e.getMessage());
throw e;
} catch (DocumentException e) {
logger.info("HtmlToPDF.generatePdf occoured DocumentException! Message:" + e.getMessage());
throw e;
}
}
/**
* html模板生成PDF文件输出
*
* @param htmlPath html模板文件路径
* @param map 要替换的字段值
* @param outputFile 输出文件形式
* @throws Exception
*/
public static void generatePdf(String htmlPath, Map<String, String> map, OutputStream outputFile) throws Exception {
Document document = null;
InputStream in = null;
try {
// 获取html String形式
String htmlStr = operateHtml(htmlPath, map);
// 创建输入html流
in = stringToInputStream(htmlStr);
// 第一步
document = new Document();
// 第二步
PdfWriter writer = PdfWriter.getInstance(document, outputFile);
// 第三步
document.open();
// 第四步 解决中文支持问题,中文不显示则给不显示的标签加上样式font-family:'SimSun';
XMLWorkerHelper.getInstance().parseXHtml(writer, document, in, Charset.forName("UTF-8"));
// 第五步
in.close();
document.close();
logger.info("PDF is generate.------------------------------");
} catch (IOException e) {
logger.info("HtmlToPDF.generatePdf occoured IOException! Message:" + e.getMessage());
throw e;
} catch (DocumentException e) {
logger.info("HtmlToPDF.generatePdf occoured DocumentException! Message:" + e.getMessage());
throw e;
} finally {
if (in != null) {
in.close();
}
if (document != null) {
document.close();
}
}
}
/**
* String转InputStream
*
* @param str
* @return
*/
private static InputStream stringToInputStream(String str) {
InputStream in = new ByteArrayInputStream(str.getBytes());
return in;
}
/**
* InputStream转String
*
* @param in
* @return
*/
@SuppressWarnings("unused")
private static String inputStreamToString(InputStream in) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = 1;
try {
while ((i = in.read()) != -1) {
baos.write(i);
}
} catch (Exception e) {
e.printStackTrace();
}
return baos.toString();
}
/**
* 读取html模板文件并替换参数值
*
* @param htmlPath html文件路径
* @param map 要替换的参数值
* @return
* @throws Exception
*/
private static String operateHtml(String htmlPath, Map<String, String> map) throws Exception {
// html字符串
String htmlStr = "";
File htmlFile = null;
try {
htmlFile = new File(htmlPath);
//获取htmlStr jsoup,建议使用,会补全缺失的**>
org.jsoup.nodes.Document html = Jsoup.parse(htmlFile,"UTF-8");
htmlStr = html.html();
// 解决中文问题
htmlStr = htmlStr.replaceAll("font-family:[^;]*;", "font-family:'SimSun';");
// 解决docx中文问题
htmlStr = htmlStr.replaceAll("width:[^;]*;", "");
htmlStr = htmlStr.replaceAll("margin-bottom:[^;]*;", "");
htmlStr = htmlStr.replaceAll("margin-left:[^;]*;", "");
htmlStr = htmlStr.replaceAll("margin-right:[^;]*;", "");
htmlStr = htmlStr.replaceAll("margin-top:[^;]*;", "");
htmlStr = htmlStr.replaceAll("p\\.[^\\}]*\\}", "");
htmlStr = htmlStr.replaceAll("span\\.[^\\}]*\\}", "");
htmlStr = htmlStr.replaceAll(""
, ""
);
//将未闭合的标签 闭合
htmlStr = expectedClosingTag(htmlStr, "(]*[^/]>)|(]*[^/]>)");
//表格线条错误粗修改
htmlStr = htmlStr.replaceAll("thin solid black", "1");
//替换特殊字段 字段形式 如: ${test}
for (Map.Entry<String, String> entry : map.entrySet()){
htmlStr = htmlStr.replaceAll("\\$\\{" + entry.getKey() + "\\}", entry.getValue());
htmlStr = htmlStr.replaceAll("\\$\\{[^\\}]*" + entry.getKey() + "[^\\}]*\\}", entry.getValue());
}
// 将未赋值的去除
htmlStr = htmlStr.replaceAll("\\$\\{[^\\}]*[^\\}]*\\}", " ");
// 将body标签内样式去掉,并加上font-family:'SimSun';解决中文不显示问题
htmlStr = htmlStr.replaceAll("]*>", "");
} catch (Exception e) {
logger.info("HtmlToPDF.operateHtml occoured Exception! Message:" + e.getMessage());
throw e;
} finally {
if (htmlFile != null) {
htmlFile.delete();
}
}
return htmlStr;
}
/**
* 处理html meta标签,使meta标签闭合
* @param htmlStr
* @param regex
* @return
*/
private static String expectedClosingTag(String htmlStr, String regex) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(htmlStr);
List<String> result = new ArrayList<String>();
while (m.find()) {
result.add(m.group());
}
for (String str : result) {
int strLen = str.length();
if (str != null && strLen > 1) {
logger.debug("In need of replacement:" + str);
htmlStr = htmlStr.replace(str, str.substring(0, strLen - 1) + "/>");
}
}
return htmlStr;
}
/**
* 获取当前操作系统
*
* @return
*/
public static String getCurrentOperatingSystem(){
String os = System.getProperty("os.name").toLowerCase();
logger.debug("---------当前操作系统是-----------" + os);
return os;
}
}
测试类:
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class HtmlToPDFTest {
@SuppressWarnings("static-access")
public static void main(String[] args) throws Exception {
/* 用log4包加载配置文件 */
// PropertyConfigurator.configure(System.getProperty("user.dir") + "\\src\\log4j.properties");
/* 用java自带peoperties加载配置文件 */
Properties props=new Properties();
try {
props.load(HtmlToPDFTest.class
.getClassLoader()
.getResourceAsStream("log4j.properties")
);
} catch (IOException e) {
e.printStackTrace();
}
String htmlFile1 = "E:/test/test1.html";
String htmlFile2 = "E:/test/test2.html";
String pdfFile1 = "E:/test/test1.pdf";
String pdfFile2 = "E:/test/test2.pdf";
Map<String, String> map = new HashMap<String, String>();
map.put("test1", "测试1");
map.put("test2", "测试2");
map.put("test3", "测试3");
map.put("test4", "测试4");
new HtmlToPDF().generatePdf(htmlFile1, map, pdfFile1);
new HtmlToPDF().generatePdf(htmlFile2, map, new FileOutputStream(pdfFile2));
}
}
maven依赖:
<dependency>
<groupId>org.xhtmlrenderergroupId>
<artifactId>core-rendererartifactId>
<version>R8version>
dependency>
<dependency>
<groupId>com.itextpdfgroupId>
<artifactId>itextpdfartifactId>
<version>5.4.0version>
dependency>
<dependency>
<groupId>com.itextpdf.toolgroupId>
<artifactId>xmlworkerartifactId>
<version>5.4.0version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.2version>
dependency>
<dependency>
<groupId>org.jsoupgroupId>
<artifactId>jsoupartifactId>
<version>1.7.2version>
dependency>