最初是希望可以通过读取网页模板,生成pdf文件并提供下载,但是经过测试js是不被解析的,如果只有图片和文字效果还是不错的。
需要注意
- 所有标签需要严格闭合
- js无效
- 所有样式需要写在head内部(不能引入外联样式)
- 动态生成条形图之类的无法转换
- html5不支持(不确定)
- 图片支持网络url,视频未测试
先贴上转换效果
- 表格分页时后效果
- 放大时
- 第一页完整显示效果
使用的模板文件 template.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>###TITLE###</title>
<style>
h2,
h4 {
text-align: center;
}
.imgdiv {
text-align: center;
}
.gridtable {
/* font-family: verdana, arial, sans-serif; */
font-size: 11px;
color: #333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
width: 100%;
text-align: center;
margin: auto;
margin-top: 20px;
margin-bottom:20px ;
}
.gridtable th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #dedede;
}
.gridtable td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #ffffff;
}
</style>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
<h2>###TITLE###</h2>
<h4>###INTRODUCE###</h4>
<p>打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市</p>
<h4>标题</h4>
<p>打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市打断的文字阿大使大赛大所多俺说的啊啊是大神打打大神打大神大神大卅大安市安市大啊大大神大神大神大安市大大安市大神大神大神大神大神大撒打算大神大神的安市</p>
<table class="gridtable">
<tr>
<th>标题1</th>
<th>标题2</th>
<th>标题3</th>
<th>标题4</th>
<th>标题5</th>
<th>标题6</th>
<th>标题7</th>
<th>标题8</th>
<th>标题9</th>
<th>标题10</th>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
<tr>
<td>内容1内容1内容1内容1内容1内1</td>
<td>内容2内容2内容2内容2内容2内容2内容2</td>
<td>内容3</td>
<td>内容4</td>
<td>内容5</td>
<td>内容6</td>
<td>内容7</td>
<td>内容8</td>
<td>内容9</td>
<td>内容10</td>
</tr>
</table>
<div class="imgdiv"><img style="max-width: 50%;" src="http://pic29.nipic.com/20130530/12174133_162640398000_2.jpg" /></div>
</body>
</html>
java代码
import com.itextpdf.text.Font;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
public class AsianFontProvider extends XMLWorkerFontProvider {
public AsianFontProvider(){
super(null, null);
}
@Override
public Font getFont(final String fontname, String encoding, float size, final int style) {
String fntname = fontname;
if (fntname == null) {
//fntname = "/font/simsun.ttf";
fntname = "宋体";
}
if (size == 0) {
size = 4;
}
return super.getFont(fntname, encoding, size, style);
}
}
如果运行在linux系统上,需要下载simsun.ttf文件到resource文件夹内
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
public class Tes {
String htmlFile = "D:"+File.separator+"template.html";
String pdfFile = "D:"+File.separator+"template2.pdf";
@Before
public void before() {
File pdf = new File(pdfFile);
if(pdf.exists())
pdf.delete();
}
@Test
public void htmp2pdf(){
Document document = null;
PdfWriter pdfWriter = null;
try {
document = new Document(PageSize.LETTER);
pdfWriter = PdfWriter.getInstance(document,
new FileOutputStream(pdfFile));
//此处设置的并没有起作用,不知道为什么
document.addAuthor("author");
document.addCreator("test");
document.addSubject("评测结果");
document.addCreationDate();
document.addTitle("HTML to PDF");
document.open();
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
//读取模板文件并且写入String中
InputStream in = new FileInputStream(htmlFile);
InputStreamReader isr = new InputStreamReader(in, "utf-8");
BufferedReader brd = new BufferedReader(isr);
StringBuffer sbf = new StringBuffer();
String line = "";
while((line=brd.readLine())!=null) {
sbf.append(line);
}
String htmlTemplete = sbf.toString();
//此处替换特定字符或者拼接html代码的处理
htmlTemplete = htmlTemplete.replaceAll("###TITLE###", "html转pdf");
htmlTemplete = htmlTemplete.replaceAll("###INTRODUCE###", "html转pdf测试");
//模板不支持svg格式图片
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(htmlTemplete.getBytes("UTF-8")), Charset.forName("utf8"), new AsianFontProvider());
System.out.println("complete");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(document!=null)
//如果不关闭则会生成空的破损的pdf
document.close();
}
}
}
依赖的jar
<!-- 生成PDF文件 start-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.8</version>
</dependency>
<!-- 生成PDF文件 end -->
遇到的问题1
ExceptionConverter: java.io.IOException: The document has no pages.
at com.itextpdf.text.pdf.PdfPages.writePageTree(PdfPages.java:112)
at com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1256)
at com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:901)
at com.itextpdf.text.Document.close(Document.java:415)
at pdf.Tes.test1(Tes.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
原因 没有加反斜杠,所有标签必须严格闭合。
遇到的问题2
com.itextpdf.tool.xml.exceptions.RuntimeWorkerException: Invalid nested tag body found, expected closing tag script.
at com.itextpdf.tool.xml.XMLWorker.endElement(XMLWorker.java:135)
at com.itextpdf.tool.xml.parser.XMLParser.endElement(XMLParser.java:397)
at com.itextpdf.tool.xml.parser.state.ClosingTagState.process(ClosingTagState.java:71)
at com.itextpdf.tool.xml.parser.XMLParser.parseWithReader(XMLParser.java:237)
at com.itextpdf.tool.xml.parser.XMLParser.parse(XMLParser.java:215)
at com.itextpdf.tool.xml.parser.XMLParser.parse(XMLParser.java:204)
at com.itextpdf.tool.xml.XMLWorkerHelper.parseXHtml(XMLWorkerHelper.java:224)
at com.itextpdf.tool.xml.XMLWorkerHelper.parseXHtml(XMLWorkerHelper.java:188)
at pdf.Tes.test1(Tes.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
尝试转换 ECharts 时出现的问题,删除 script 标签恢复正常