利用velocity + itextpdf 实现动态html转pdf文件导出

1. 书写html排版(你想要导出的pdf的样式模板),注意这边写html不能使用到几个css样式属性(position,folat,font等)具体有哪些自己写了就清楚了,因为itext转pdf的时候这几种样式不能识别。

2.写完html样式排版后把他改写成velocity模板引擎的.vm文件,使用velocity的语法填充该.vm文件

image.png

3. 初始化模板引擎配置

public class VelocityHelper {

    private static VelocityEngine ve = new VelocityEngine();

    private static void initVelocityEngine(String path){
        ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, path);// 这是模板所在路径
        ve.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
        ve.setProperty(Velocity.INPUT_ENCODING, "UTF-8");//指定编码格式,避免生成模板就造成乱码,影响到转pdf后的文件
        ve.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
        ve.init();
    }
    /**
     *  得到模板引擎渲染数据后的文件流
     * @param templatePath 模板所在位置
     * @param out 得到输出流
     * @param paramMap 模板数据k-y
     * @param dataList 模板数据集合
     * @return 流
     */
    public static Writer getWriterByTemplate(String templatePath, OutputStream out, Map paramMap, List dataList){

        File file = new File(templatePath);
        String path = file.getParent();

        initVelocityEngine(path);

        Template template = ve.getTemplate(file.getName(), "utf-8");

        VelocityContext ctx = new VelocityContext();
        ctx.put("paramMap", paramMap);
        ctx.put("dataList", dataList);
        ctx.put("dateformat", new DateUtil());
        Writer bw;
        if(null != out)
            bw = new BufferedWriter(new OutputStreamWriter(out));
        else
            bw = new StringWriter();
        template.merge(ctx, bw);
        return bw;
    }
}

4. 得到流对象先放着,因为itext的方法parseXHtml查看源码

/**
     * @param  writer 备用写对象
     * @param doc 创建的document对象
     * @param in 转pdf的输入流文件
     * @param charset 编码格式
     * @throws IOException if the {@link InputStream} could not be read.
     */
    public void parseXHtml(final PdfWriter writer, final Document doc, final InputStream in, final Charset charset) throws IOException {
        parseXHtml(writer,doc,in, XMLWorkerHelper.class.getResourceAsStream("/default.css"), charset);
    }

    /**
     * @param writer the writer to use
     * @param doc the document to use
     * @param in the {@link InputStream} of the XHTML source.
     * @param in the {@link CssFiles} of the css files.
     * @param charset the charset to use
     * @throws IOException if the {@link InputStream} could not be read.
     */
    public void parseXHtml(final PdfWriter writer, final Document doc, final InputStream in, final InputStream inCssFile, final Charset charset, final FontProvider fontProvider) throws IOException {
        CssFilesImpl cssFiles = new CssFilesImpl();
        if (inCssFile != null)
            cssFiles.add(getCSS(inCssFile));
        else
            cssFiles.add(getDefaultCSS());
        StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
        HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(fontProvider));
        hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(getDefaultTagProcessorFactory());
        HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
        Pipeline pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
        XMLWorker worker = new XMLWorker(pipeline, true);
        XMLParser p = new XMLParser(true, worker, charset);
        if (charset != null)
            p.parse(in, charset);
        else
            p.parse(in);
    }

所以这边我们要准备(PdfWriter对象,document对象,html流文件,编码)四个元素对象。所以第五步准备原料

5.准备元素

  • 准备Document和PdfWriter
#都是itextpdf包的对象
 Document document = new Document();
 PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream);// outputStream可以自己指定位置或者是HttpServletResponse得到的输出流
 pdfWriter.setTagged();
 document.open();
  • 准备html输入流文件,因为第三步得到的writer对象,我们可以进一步把他转换成输入流
Writer writer = VelocityHelper.getWriterByTemplate(path, null, map, dtoList);
//        log.info("转换的文本内容为===============" + writer.toString());
//输出转输入流
InputStream in = new ByteArrayInputStream(writer.toString().getBytes(Charset.defaultCharset()));

使用完之后记得关闭流剩下编码直接指定编码就好了(Charset.forName("UTF-8"))

6.调用方法

XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document, inputStream, Charset.forName("UTF-8"));

如果文件带中文的话解决中文不显示问题要使用这个方法

//解决中文不显示问题
        XMLWorkerFontProvider fontProvider = getFontProvider();
        XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document, inputStream,
                null, Charset.forName("UTF-8"), fontProvider);

getFontProvider方法如下:

private static XMLWorkerFontProvider getFontProvider(){

        XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {
            @Override
            public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {

                //你的字体文件的位置
                //这里把所有字体都设置为宋体了,可以根据fontname的值设置字体
                String yaHeiFontName = getClass().getClassLoader().getResource("font/msyh.ttc").toString();//系统文字文件地址位置,我这边直接放在项目里面了
                yaHeiFontName += ",1";//如果文件是.ttc结尾文件要加上这个,如果不是可以去掉
                Font yaHeiFont;
                Font font = null;
                try {
                    font = new Font(com.itextpdf.text.pdf.BaseFont.createFont(yaHeiFontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED));
                    font.setStyle(style);
                    font.setColor(color);
                    if (size>0){
                        font.setSize(size);
                    }
                } catch (DocumentException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return font;
            }
        };
        return fontProvider;
    }

7.关闭文档对象即可输出流对象

document.close();

然后后面的样式是怎样的你们自己确定调整就好了

你可能感兴趣的:(利用velocity + itextpdf 实现动态html转pdf文件导出)