java通过html模板转pdf文件(中文可显示)

最初是希望可以通过读取网页模板,生成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 标签恢复正常

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值