当前位置: 移动技术网 > IT编程>开发语言>Java > java根据模板动态生成PDF实例

java根据模板动态生成PDF实例

2019年07月22日  | 移动技术网IT编程  | 我要评论

林丹谢杏芳婚纱照,寇哥骑行网,幼儿园新生入园须知

一、需求说明:

根据业务需要,需要在服务器端生成可动态配置的pdf文档,方便数据可视化查看。

二、解决方案:

itext+freemarker+jfreechart生成可动态配置的pdf文档

itext有很强大的pdf处理能力,但是样式和排版不好控制,直接写pdf文档,数据的动态渲染很麻烦。

freemarker能配置动态的html模板,正好解决了样式、动态渲染和排版问题。

jfreechart有这方便的画图api,能画出简单的折线、柱状和饼图,基本能满足需要。

三、实现功能:

1、能动态配置pdf文档内容

2、能动态配置中文字体显示

3、设置自定义的页眉页脚信息

4、能动态生成业务图片

5、完成pdf的分页和图片的嵌入

四、主要代码结构说明:

1、component包:pdf生成的组件 对外提供的是pdfkit工具类和headerfooterbuilder接口,其中pdfkit负责pdf的生成,headerfooterbuilder负责自定义页眉页脚信息。

2、builder包:负责pdf模板之外的额外信息填写,这里主要是页眉页脚的定制。

3、chart包:jfreechart的画图工具包,目前只有一个线形图。

4、test包:测试工具类

5、util包:freemarker等工具类。

五、关键代码说明:

1、模板配置

 <!doctype html public "-//w3c//dtd xhtml 1.0 strict//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  <meta http-equiv="content-style-type" content="text/css"/>
  <title></title>
  <style type="text/css">
    body {
      font-family: pingfang sc light;
    }
    .center{
      text-align: center;
      width: 100%;
    }
  </style>
</head>
<body>
<!--第一页开始-->
<div class="page" >
  <div class="center"><p>${templatename}</p></div>
  <div><p>itext官网:${itexturl}</p></div>
  <div><p>freemarker官网:${freemarkerurl}</p></div>
  <div><p>jfreechart教程:${jfreecharturl}</p></div>
  <div>列表值:</div>
  <div>
    <#list scores as item>
      <div><p>${item}</p></div>
    </#list>
  </div>
</div>
<!--第一页结束-->
<!---分页标记-->
<span style="page-break-after:always;"></span>
<!--第二页开始-->
<div class="page">
  <div>第二页开始了</div>
  <!--外部链接-->
  <p>百度图标</p>
  <div>
    <img src="${imageurl}" alt="百度图标" width="270" height="129"/>
  </div>
  <!--动态生成的图片-->
  <p>气温变化对比图</p>
  <div>
    <img src="${picurl}" alt="我的图片" width="500" height="270"/>
  </div>
</div>


<!--第二页结束-->
</body>
</html>

2、获取模板内容并填充数据

/**
 * @description 获取模板
 */
public static string getcontent(string filename,object data){

  string templatepath=getpdftemplatepath(filename);//根据pdf名称查找对应的模板名称
  string templatefilename=gettemplatename(templatepath);
  string templatefilepath=gettemplatepath(templatepath);
  if(stringutils.isempty(templatepath)){
    throw new freemarkerexception("templatepath can not be empty!");
  }
  try{
    configuration config = new configuration(configuration.version_2_3_25);//freemarker配置
    config.setdefaultencoding("utf-8");
    config.setdirectoryfortemplateloading(new file(templatefilepath));//注意这里是模板所在文件夹,不是文件
    config.settemplateexceptionhandler(templateexceptionhandler.rethrow_handler);
    config.setlogtemplateexceptions(false);
    template template = config.gettemplate(templatefilename);//根据模板名称 获取对应模板
    stringwriter writer = new stringwriter();
    template.process(data, writer);//模板和数据的匹配
    writer.flush();
    string html = writer.tostring();
    return html;
  }catch (exception ex){
    throw new freemarkerexception("freemarkerutil process fail",ex);
  }
}

3、导出模板到pdf文件

/**
   * @description   导出pdf到文件
   * @param filename 输出pdf文件名
   * @param data   模板所需要的数据
   *
   */
public string exporttofile(string filename,object data){
   string htmldata= freemarkerutil.getcontent(filename, data);//获取freemarker的模板数据
  if(stringutils.isempty(savefilepath)){
    savefilepath=getdefaultsavepath(filename);//设置pdf文件输出路径
  }
  file file=new file(savefilepath);
  if(!file.getparentfile().exists()){
    file.getparentfile().mkdirs();
  }
  fileoutputstream outputstream=null;
  try{
    //设置输出路径
    outputstream=new fileoutputstream(savefilepath);
    //设置文档大小
    document document = new document(pagesize.a4);//itext新建pdf文档
    pdfwriter writer = pdfwriter.getinstance(document, outputstream);//设置文档和输出流的关系

    //设置页眉页脚
    pdfbuilder builder = new pdfbuilder(headerfooterbuilder,data);
    builder.setpresentfontsize(10);
    writer.setpageevent(builder);

    //输出为pdf文件
    converttopdf(writer,document,htmldata);
  }catch(exception ex){
    throw new pdfexception("pdf export to file fail",ex);
  }finally{
    ioutils.closequietly(outputstream);
  }
  return savefilepath;

}

4、测试工具类

 public string createpdf(object data, string filename){
      //pdf保存路径
      try {
        //设置自定义pdf页眉页脚工具类
        pdfheaderfooter headerfooter=new pdfheaderfooter();
        pdfkit kit=new pdfkit();
        kit.setheaderfooterbuilder(headerfooter);
        //设置输出路径
        kit.setsavefilepath("/users/fgm/desktop/pdf/hello.pdf”);//设置出书路径
        string savefilepath=kit.exporttofile(filename,data);
        return savefilepath;
      } catch (exception e) {
        log.error("pdf生成失败{}", exceptionutils.getfullstacktrace(e));
        return null;
      }
    
    }
  
 public static void main(string[] args) {
     reportkit360 kit=new reportkit360();
        templatebo templatebo=new templatebo();//配置模板数据
        templatebo.settemplatename("hello itext! hello freemarker! hello jfreechart!");
        templatebo.setfreemarkerurl("http://www.zheng-hang.com/chm/freemarker2_3_24/ref_directive_if.html");
        templatebo.setitexturl("http://developers.itextpdf.com/examples-itext5");
  
  templatebo.setjfreecharturl("http://www.yiibai.com/jfreechart/jfreechart_referenced_apis.html");
    templatebo.setimageurl("https://ss0.bdstatic.com/5av1bjqh_q23odcf/static/superman/img/logo/bd_logo1_31bdc765.png");
    
    
       list<string> scores=new arraylist<string>();
        scores.add("90");
        scores.add("95");
        scores.add("98");
        templatebo.setscores(scores);
        list<line> linelist=gettemperaturelinelist();
        temperaturelinechart linechart=new temperaturelinechart();
        string picurl=linechart.draw(linelist,0);//自定义的数据画图
        templatebo.setpicurl(picurl);
        string path= kit.createpdf(templatebo,"hello.pdf");
      system.out.println(path);
    
    }

六、生成效果图:

七、项目完整代码

1、github地址:

八、遇到的坑:

1、freemarker配置模板文件样式,在实际pdf生成过程中,可能会出现一些不一致的情形,目前解决方法,就是换种方式调整样式。

2、字体文件放在resource下,在打包时会报错,运行mvn -x compile 会看到详细错误:

这是字体文件是二进制的,而maven项目中配置了资源文件的过滤,不能识别二进制文件导致的,plugins中增加下面这个配置就好了:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
  <!--增加的配置,过滤ttf文件的匹配-->
  <plugins>
    <plugin>
      <groupid>org.apache.maven.plugins</groupid>
      <artifactid>maven-resources-plugin</artifactid>
      <version>2.7</version>
      <configuration>
        <encoding>utf-8</encoding>
        <nonfilteredfileextensions>
          <nonfilteredfileextension>ttf</nonfilteredfileextension>
        </nonfilteredfileextensions>
      </configuration>
    </plugin>
  </plugins>
</build>

3、pdf分页配置:

在ftl文件中,增加分页标签: <span style="page-break-after:always;"></span>

九、 完整maven配置:

<!--pdf生成 itext-->
 
 <dependency>
    <groupid>com.itextpdf</groupid>
    <artifactid>itextpdf</artifactid>
    <version>5.4.2</version>
   </dependency>
 <dependency>
  <groupid>com.itextpdf.tool</groupid>
  <artifactid>xmlworker</artifactid>
  <version>5.4.1</version>
</dependency>
<dependency>
  <groupid>com.itextpdf</groupid>
  <artifactid>itext-asian</artifactid>
  <version>5.2.0</version>
</dependency>
<dependency>
  <groupid>org.xhtmlrenderer</groupid>
  <artifactid>flying-saucer-pdf</artifactid>
  <version>9.0.3</version>
</dependency>
<!--freemarker-->
<dependency>
  <groupid>org.freemarker</groupid>
  <artifactid>freemarker</artifactid>
  <version>2.3.26-incubating</version>
</dependency>
<!--jfreechart-->
<dependency>
  <groupid>jfreechart</groupid>
  <artifactid>jfreechart</artifactid>
  <version>1.0.0</version>
</dependency>
<!--log-->
<dependency>
  <groupid>ch.qos.logback</groupid>
  <artifactid>logback-core</artifactid>
  <version>1.0.13</version>
</dependency>
<dependency>
  <groupid>ch.qos.logback</groupid>
  <artifactid>logback-classic</artifactid>
  <version>1.0.13</version>
</dependency>
<dependency>
  <groupid>ch.qos.logback</groupid>
  <artifactid>logback-access</artifactid>
  <version>1.0.13</version>
</dependency>
<dependency>
  <groupid>org.slf4j</groupid>
  <artifactid>slf4j-api</artifactid>
  <version>1.7.5</version>
</dependency>
<dependency>
  <groupid>org.slf4j</groupid>
  <artifactid>log4j-over-slf4j</artifactid>
  <version>1.7.21</version>
</dependency>
<!--util-->
<dependency>
  <groupid>com.google.guava</groupid>
  <artifactid>guava</artifactid>
  <version>20.0</version>
</dependency>
<dependency>
  <groupid>org.projectlombok</groupid>
  <artifactid>lombok</artifactid>
  <version>1.14.8</version>
</dependency>
<dependency>
  <groupid>org.apache.commons</groupid>
  <artifactid>commons-io</artifactid>
  <version>1.3.2</version>
</dependency>
<dependency>
  <groupid>commons-lang</groupid>
  <artifactid>commons-lang</artifactid>
  <version>2.6</version>
</dependency>
<!--servlet-->
<dependency>
  <groupid>javax.servlet</groupid>
  <artifactid>servlet-api</artifactid>
  <version>2.5</version>
</dependency>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网