iText实现html转pdf

来源:互联网 发布:淘宝客贷条件 编辑:程序博客网 时间:2024/05/17 02:57

   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 0