iText实现html转pdf

   iText是一个文件转换的jar包,可实现html文件,xml文件转PDF,word的jar包。

maven依赖:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.9</version>
</dependency>

<dependency>
    <groupId>com.itextpdf.tool</groupId>
    <artifactId>xmlworker</artifactId>
    <version>5.5.9</version>
</dependency>

使用首先要到的一个大问题就是不能处理中文,之前用网上教的字体是一直报这个错,com.itextpdf.text.DocumentException: Font "STSongStd-Light" with "UniGB-UCS2-H" is not recognized。
在网上痛苦的找了很久,大家给的最多的答案就是去改jar的引用路径,这方法太不靠谱了,jar一直在升级,你总不能每次都去改吧,最后终于找到了解决办法,问题根源就是这个工具没有在jar包中打包中文字体,不过它给我们提供了一个字体设置工厂,上代码,
public class PDFUtil {
    private static final Logger logger = LoggerFactory.getLogger(PDFUtil.class);
    private static String fontPath = "/Users/feixiaobo/Downloads/simsun.ttf";
    public static InputStream htmlToPDF(InputStream htmlInputStream) {
        ByteArrayOutputStream out = null;
        ByteArrayInputStream inputStream = null;
        Document document = new Document();
        XMLWorkerFontProvider provider = new XMLWorkerFontProvider();
        provider.register(fontPath);
        try {
            out = new ByteArrayOutputStream();
            PdfWriter writer = PdfWriter.getInstance(document, out);
            document.open();
            XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new BufferedInputStream(htmlInputStream), Charset.forName("utf-8"), provider);
            document.close();
            inputStream = new ByteArrayInputStream(out.toByteArray());
        
       } catch (DocumentException e) {
            logger.error(e.getMessage(), e);
       } catch (IOException e) {
            document.close();
            logger.error(e.getMessage(), e);
       } 
finally {
                  if (inputStream != null) {                
                   try {                    
                         inputStream.close();                
                      } catch (IOException e) {                   
                          logger.error(e.getMessage(), e);               
                       }            
                    }           
                  if (out != null) {               
                    try {                    
                         out.close();                
                       } catch (IOException e) {                   
                         logger.error(e.getMessage(), e);               
                        }            
                       }        
                  }        return inputStream;    
     }
	
    public static void main(String[] args) throws IOException{
      String html = "/Users/feixiaobo/Desktop/test.html";
      String pdf = "/Users/feixiaobo/Desktop/test.pdf";
      File pdfFile = new File(pdf);
      InputStream inputStream = htmlToPDF(new FileInputStream(new File(html)));
      try{
          if(!pdfFile.exists()){
            pdfFile.createNewFile();
           }
        }catch (IOException e ){
	   //
       }
     IOUtil.copyCompletely(inputStream,new FileOutputStream(pdf));
     }
  }
这样的一个方法便实现了将html 流转为pdf流,其中解决中文问题的关键代码
XMLWorkerFontProvider provider = new XMLWorkerFontProvider();
provider.register(fontPath);
我自己下载了一个宋体字体,然后通过这个方法引入中文字体,simsun.ttf便是宋体字体,不过html模版里的字体要全部改为宋体,至此中文问题解决了,传入一个html文件的输入流掉用这个方法便得到了一个PDF输出流,特别注意,这个方法返回的是一个字节流,不是字符流,如果你用字符流的方法写入文件生成的PDF文件是打不开的。
那么很多人又遇到问题了,字节流如何写入文件,当然网上有很多方法,通过定义一个缓冲区然后用InputStream的read()方法一段一段读,再用OutputStream的write()方法一段一段写,这里我给大家一个很好(懒)的方法,
IOUtil.copyCompletely(InputStream input, OutputStream output);这是javaIO包直接给我们封装好的方法,看下这个方法的源码,
public static void copyCompletely(InputStream input, OutputStream output) throws IOException {
    if(output instanceof FileOutputStream && input instanceof FileInputStream) {
        try {
            FileChannel buf1 = ((FileOutputStream)output).getChannel();
            FileChannel ignore1 = ((FileInputStream)input).getChannel();
            ignore1.transferTo(0L, 2147483647L, buf1);
            ignore1.close();
            buf1.close();
            return;
        } catch (Exception var6) {
            ;
        }
    }

    byte[] buf = new byte[8192];

    while(true) {
        int ignore = input.read(buf);
        if(ignore < 0) {
            try {
                input.close();
            } catch (IOException var5) {
                ;
            }

            try {
                output.close();
            } catch (IOException var4) {
                ;
            }

            return;
        }

        output.write(buf, 0, ignore);
    }
}
这个方法会先判断输入流是字节流还是文件流,然后根据不同的流选择不同的方法,就不用我们自己去判断到底是字符流还是字符流了,无脑调这个方法便是,当然它对字节流的实现还是依然是我上面说的方法,但是不用我们自己写了啊。
最后提一点关于流要注意的问题,我们用完流之后一定记得关闭流啊,否则会有各种问题的,还需注意的是我们关闭流的代码的位置,不要觉得我上面的代码太冗余了,流的关闭不应该放在try{}catch(){}中,为什么呢?如果你的代码执行到中途抛异常了,而你关闭流的代码在异常代码后面,那问题就来了,你关闭流的代码已经执行不到了,各个流的关闭也不要写在一个try{}catch(){}中,还是这个问题,close()方法会抛异常,如果一个流的close()方法抛异常流,就会导致它后面的流执行不到关闭流的代码。还有上面方法中第一个document.close();不可省略,document不关闭,转换后的流是写不到out里的,那样生成的PDF文件是空,不能打开。第二个document.close()是因为.parseXHtm()方法会抛异常,如果这里抛了异常,那么后面的close()便执行不到了,所以需要在异常处理里关闭。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值