zoukankan      html  css  js  c++  java
  • itextpdf freemarker渲染

    现有需求涉及到打印pdf操作,简单找了俩种方式

    1. 在现有的模板上进行编辑,操作难度比较大
    2. 通过freemarker生成静态页面,在进行转换html,完美。

    关于动态生成pdf,网上参考的挺多的,看来看去还是觉得通过FreeMarker+IText生成pdf最为简单
    参考地址 https://www.cnblogs.com/yunfeiyang-88/p/10984740.html
    github demo地址 https://github.com/chywx/spring-boot-pdf/blob/freemarker-print/src/main/java/cn/chendahai/html2pdf/JavaToPdfHtmlFreeMarkerBet.java

    撸起来

    建立springboot工程
    添加maven依赖

        <!-- freemarker依赖 -->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
    
        <!-- itextpdf依赖 -->
        <dependency>
          <groupId>com.itextpdf</groupId>
          <artifactId>itextpdf</artifactId>
          <version>5.5.13.2</version>
        </dependency>
    
        <!-- 更好的css支持 -->
        <dependency>
          <groupId>org.xhtmlrenderer</groupId>
          <artifactId>flying-saucer-pdf</artifactId>
          <version>9.1.20</version>
        </dependency>
    

    application.properties配置freemarker,默认配置

    spring.freemarker.charset=UTF-8
    spring.freemarker.suffix=.ftl
    spring.freemarker.content-type=text/html; charset=utf-8
    spring.freemarker.template-loader-path=classpath:/templates
    spring.mvc.static-path-pattern=/static/**
    

    测试代码

    public class JavaToPdfHtmlFreeMarkerBet {
    
        private static final String DEST = "target/bet-gg.pdf";
        private static final String HTML = "index7.html";
    
        private static final String IMG_PATH = "file:///D:/project/javaproject/spring-boot-pdf/src/main/resources/static/";
    
        private static Configuration freemarkerCfg;
    
        static {
            freemarkerCfg = new Configuration();
            //freemarker的模板目录
            try {
                freemarkerCfg.setDirectoryForTemplateLoading(new File("src/main/resources/templates/betPrint"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws IOException, DocumentException, com.lowagie.text.DocumentException {
            Map<String, Object> data = new HashMap();
            data.put("name", "dahai");
            String content = JavaToPdfHtmlFreeMarkerBet.freeMarkerRender(data, HTML);
            JavaToPdfHtmlFreeMarkerBet.createPdf(content, DEST);
        }
    
        /**
         * freemarker渲染html
         */
        public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
            Writer out = new StringWriter();
            try {
                // 获取模板,并设置编码方式
                Template template = freemarkerCfg.getTemplate(htmlTmp);
                template.setEncoding("UTF-8");
                // 合并数据模型与模板
                template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
                out.flush();
                return out.toString();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    out.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            return null;
        }
    
        public static void createPdf(String content, String dest) throws IOException, com.lowagie.text.DocumentException {
            ITextRenderer render = new ITextRenderer();
            // 解析html生成pdf
            render.setDocumentFromString(content);
            //解决图片相对路径的问题
            render.getSharedContext().setBaseURL(IMG_PATH);
            render.layout();
            render.createPDF(new FileOutputStream(dest));
        }
    }
    

    web环境

    获取模板的话可以直接通过注入FreeMarkerConfigurer来获取

        @Autowired
        FreeMarkerConfigurer freeMarkerConfigurer;
    
    Template template = freeMarkerConfigurer.getConfiguration().getTemplate("betPrint/print_match.ftl");
    

    设置边距

    由于是通过模板进行渲染,所以边距需要前端来进行控制

    @page {
        margin: 0in 0.1in 0in 0.1in;
        mso-header-margin: .5in;
        mso-footer-margin: .5in;
        mso-page-orientation: landscape;
    }
    

    但是打印的时候如果选择实际大小,那会导致前面的配置失效

    pdf流形式返回

    该实例是直接在本地磁盘生成pdf,如果是web环境下,可以通过生成流的方式,直接返回给客户端,避免了磁盘io
    方式就是将
    render.createPDF(new FileOutputStream(dest));
    修改为
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    render.createPDF(outputStream);

    总结:

    1. html的格式要求符合xml格式,必须要有闭合标签。比如<input />只能写成<input></input>
    2. 由于这是服务端生成的,自然跟客户端扯不上关系,这一点很好。但是跟window和linux还是有些细小的区别。比如linux字体的最小为12px
    3. CSS有些语法不支持,比如C3就不支持
    4. 加载图片可以使用file://协议,linux也是支持的。还有,简单起见,可以直接使用http加载网络图片
    5. 由于是通过模板渲染,边距,分页等设置就是前端的事了 比如height: 100%;box-sizing: border-box;即可实现
  • 相关阅读:
    OSGI简介
    公司僵尸帐号引发了一系列的入侵事件-细说密码强度验证的重要性
    为其他对象提供一种代理以控制对这个对象的访问-代理模式
    运用共享技术有效地支持大量细粒度的对象-享元模式
    移动APP为什么要开发两套Android和IOS-桥接模式
    非法疫苗引发的思考 -外观模式
    你们还记得张江男、张江女两张图片吗?-装饰模式
    一个程序员的蜕变(我是如何成为架构师的)
    公司新加了一台友宝自动售货机引发的思考-适配器模式
    程序员如何应对北上广高房价示例解说-建造者模式
  • 原文地址:https://www.cnblogs.com/chywx/p/13785529.html
Copyright © 2011-2022 走看看