FreeMarker(二):利用FreeMarker转pdf

1. 设计需求

订票成功后,生成一个pdf 文件,用户打印入场票,门票大致如下所示: 输入图片说明

2. 设计思想

  • 1). 使用FreeMarker 转换 ftl(就是FreeMarker 魔板文件),生成HTML
  • 2). 使用jtidy库将 HTML转换成 对格式要求严格的 XHTML
  • 3 ) . 使用Itext 库将XHTML转换成PDF

3. Demo 创建

简介:本项目是在Maven 的环境中搭建的,其pom.xml 主要导入的依赖如下:

     <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.6</version>
        </dependency>

        <dependency>
            <groupId>net.sf.jtidy</groupId>
            <artifactId>jtidy</artifactId>
            <version>r938</version>
        </dependency>

3.1 FreeMarker 魔板转换成pdf 源码如下:

public class FreeMarkToHtml {


    /**
     * 通过路径 和文件名称后去魔板
     *
     * @param templateFilePath
     * @param templateFileName
     * @return
     */
    public static Template getTemplate(String templateFilePath, String templateFileName) {
        try {
            Configuration cfg = new Configuration();
            cfg.setClassicCompatible(true);

            TemplateLoader templateLoader = new FileTemplateLoader(new File(
                    templateFilePath));
            cfg.setTemplateLoader(templateLoader);
            return cfg.getTemplate(templateFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param templateFilePath
     * @param templateFileName 加载的模板文件名
     * @param replaceData
     * @param outFile          生成指定文件
     * @return 成功,返回文件名;失败,返回null。
     */
    public static String freemarkToHtml(String templateFilePath, String templateFileName, Map<String, Object> replaceData,
                                        String outFile) {

        String path = null;
        Writer out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(outFile), "UTF-8"));
            Template temp = getTemplate(templateFilePath, templateFileName);
            temp.setEncoding("UTF-8");
            temp.process(replaceData, out);
            path = outFile;

        } catch (IOException e) {
            e.printStackTrace();
            path = null;
        } catch (TemplateException e) {
            e.printStackTrace();
            path = null;
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return path;
    }
}

3.1 使用jtidy库将 HTML转换成 对格式要求严格的 XHTML源码

/**
 * 将html 转换成为严格的XHTML
 */
public class Html2Xhtml {

    /**
     * 转化类
     *
     * @param html  html文件输入路径(带文件名称)
     * @param xhtml xhtml文件输入路径(带文件名称)
     * @return
     */
    public static String html2Xhtml(String html, String xhtml) {

        String path = null;
        try {
            FileInputStream fin = new FileInputStream(html);
            ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
            int data = -1;
            while ((data = fin.read()) != -1) {
                byteArrayOut.write(data);
            }
            fin.close();
            byte[] htmlFileData = byteArrayOut.toByteArray();

            byteArrayOut.close();

            ByteArrayInputStream tidyInput = new ByteArrayInputStream(
                    htmlFileData);
            ByteArrayOutputStream tidyOut = new ByteArrayOutputStream();
            Tidy tidy = new Tidy();
            tidy.setInputEncoding("UTF-8");
            tidy.setOutputEncoding("UTF-8");
            tidy.setShowWarnings(false);
            tidy.setIndentContent(true);
            tidy.setSmartIndent(true);
            tidy.setIndentAttributes(false);
            tidy.setMakeClean(true);
            tidy.setQuiet(true);
            tidy.setWord2000(true);
            tidy.setXHTML(true);
            tidy.setErrout(new PrintWriter(System.out));

            tidy.parse(tidyInput, tidyOut);
            tidyInput.close();
            tidyOut.writeTo(new FileOutputStream(xhtml));
            tidyOut.flush();
            tidyOut.close();
            path = xhtml;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            path = null;
        } catch (IOException e) {
            e.printStackTrace();
            path = null;
        }

        return path;
    }

}

3.3 使用Itext 库将XHTML转换成PDF

/**
 * @Description: xhtml  --> pdf
 * @Author: liupenghao
 * @Date: 2018/4/17 ❤❤ 11:16
 */
public class XHtml2Pdf {

    /**
     * 转化方法
     *
     * @param html html文件输入路径(带文件名称)
     * @param pdf  pdf文件输出路径(带文件名称)
     */
    public static void XHtml2Pdf(String html, String pdf)
            throws FileNotFoundException, IOException, DocumentException,
            CssResolverException {

        int i = html.lastIndexOf(".html");
        String xhtml = null;
        xhtml = html.substring(0, i) + ".xhtml";
        xhtml = Html2Xhtml.html2Xhtml(html, xhtml);

        if (xhtml != null) {
            Document document = new Document();
            PdfWriter writer = PdfWriter.getInstance(document,
                    new FileOutputStream(pdf));
            document.open();
            FontProvider fontProvider = new FontProvider();
            fontProvider.addFontSubstitute("lowagie", "garamond");
            fontProvider.setUseUnicode(true);
            // 使用我们的字体提供器,并将其设置为unicode字体样式
            CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
            HtmlPipelineContext htmlContext = new HtmlPipelineContext(
                    cssAppliers);
            htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
            CSSResolver cssResolver = XMLWorkerHelper.getInstance()
                    .getDefaultCssResolver(true);
            Pipeline<?> pipeline = new CssResolverPipeline(cssResolver,
                    new HtmlPipeline(htmlContext, new PdfWriterPipeline(
                            document, writer)));
            XMLWorker worker = new XMLWorker(pipeline, true);
            XMLParser p = new XMLParser(worker);

            File input = new File(xhtml);
            p.parse(new InputStreamReader(new FileInputStream(input), "UTF-8"));
            document.close();
        }

    }


}

3.4 启动类编写

/**
 * 描述:
 *
 * @author liupenghao
 * @create 2018-04-17 9:58
 **/
public class ApplicationStart {
    public static void main(String[] args) {

        URL url = Thread.currentThread().getContextClassLoader().getResource("");

        Map replaceData = initData();

        FreeMarkToHtml.freemarkToHtml(url.getPath(), "template.ftl", replaceData, url.getPath() + "result.html");

        try {
            XHtml2Pdf.XHtml2Pdf(url.getPath() + "result.html", url.getPath() + "result.pdf");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (CssResolverException e) {
            e.printStackTrace();
        }
    }

    public static HashMap<String, Object> initData() {
        HashMap<String, Object> needReplaceMapData = new HashMap<String, Object>();
        /******************************************单个属性************************************/
        needReplaceMapData.put("name", "刘亦菲");


        /******************************************list 属性添加***********************************/
        List<Student> students = new ArrayList<Student>();
        for (int i = 0; i < 2; i++) {
            Student student = new Student();
            student.setId(i);
            student.setName(" 葫芦娃" + i + "号");
            students.add(student);
        }
        needReplaceMapData.put("students", students);

        /******************************************日期 ***********************************/
        needReplaceMapData.put("date", new Date());

        needReplaceMapData.put("showDate", true);

        needReplaceMapData.put("imgUrl", "http://n.sinaimg.cn/translate/344/w700h1244/20180410/B_F_-fyzeyqa1740187.jpg");

        needReplaceMapData.put("description", "描述                        一只猫");
        return needReplaceMapData;
    }
}

3.5 中文乱码的解决

/**
 * @Description: 字体提供类, 更改 默认的字体
 * @Author: liupenghao
 * @Date: 2018/4/17 ❤❤ 11:19
 */
public class FontProvider extends XMLWorkerFontProvider {

    public FontProvider() {
        super(null, null);
    }

    @Override
    public Font getFont(final String fontname, String encoding, float size,
                        final int style) {

        String fntname = fontname;
        if (fntname == null) {
            fntname = "宋体";
        }
        return super.getFont(fntname, encoding, size, style);
    }
}

4. 项目源码:

点击下载:github

猜你喜欢

转载自my.oschina.net/ahusky/blog/1796958