利用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();

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,635评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,543评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,083评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,640评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,640评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,262评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,833评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,736评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,280评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,369评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,503评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,870评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,340评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,460评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,909评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,512评论 2 359

推荐阅读更多精彩内容