`
elicer
  • 浏览: 133347 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

使用 flying saucer 来生成 PDF

阅读更多

最近产品开发遇到一个比较棘手的问题,我们产品的PDF 生成这快是用Itext 来做的,因为pdf layout比较复杂导致生成pdf的代码写的比较复杂,现在来了一个新的需求,许多新上线的国家想用自己的页面layout跟样式,这就要求我们pdf 生成这块要给每个上线国家做扩展,但是我们没有用pdf template,导致layout的change 涉及到大量的代码要重写,而且每来一个新的国家这部分代码就要重写一下。 从做产品的角度,这样的change 显然是不能接受的,于是就想是不是有跟好的方法可以解决这样的问题,现在网上有很多通过解析html 生成pdf的框架,这就是我要找的方向,经过一段时间研究发现有一个很有用的pdf 生成框架flying saucer ,它不光可以可以解析html/xhtml 生成pdf,就连这些页面使用的css也可以解析并在pdf中反映出来,这不就是我想要的吗?pdf生成逻辑完全被剥离开来,开发者完全不用操心pdf是 怎么生成的,我们只要给每个要生成的pdf做一个html/xhtml的模板并apply相应的样式css(按照business 要求的layout 跟样式) 完全不用写任何的pdf 生成代码,就能够给不同的国家生成不同的pdf.

以下是一段实例代码

<?xml version="1.0" encoding="UTF-8"?>
<!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>
        <title>Sample PDF Generation</title>
        <style type="text/css"> b { color: green; } </style>
    </head>
    <body>
        <p>
            <b>Greetings Earthlings!</b>
            We've come for your Java.
        </p>
    </body>
</html>

 看下它的pdf生成代码

package flyingsaucerpdf;

import java.io.*;
import com.lowagie.text.DocumentException;
import org.xhtmlrenderer.pdf.ITextRenderer;

public class FirstDoc {
    
    public static void main(String[] args) 
            throws IOException, DocumentException {
        String inputFile = "samples/firstdoc.xhtml";
        String url = new File(inputFile).toURI().toURL().toString();
        String outputFile = "firstdoc.pdf";
        OutputStream os = new FileOutputStream(outputFile);
        
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(url);
        renderer.layout();
        renderer.createPDF(os);
        
        os.close();
    }
}

 我们可以看到生成逻辑非常的简单。 当然在实际使用中我们不会这样做的,我们要生成的pdf template 都不是静态的页面,都需要绑定值的。所以通常的做法是我们会写一个filter 拦截所以的请求,如果请求中有生成pdf的参数我们就把这个请求的response 生成pdf.

 

比如我们要生成一个report 的pdf 是一个JSF的application,首先我们要做一个resport  xhtml的template,生成pdf的请求就相当于对此pdf teamplate页面的访问,当然要pass in 一个参数来告诉我们的filter这个请求返回的结果是否要生成pdf

...
<h:dataTable styleClass="companiesTable"
             value="#{topCompaniesBean.companiesList}" 
             var="company" 
             cellpadding="0" cellspacing="0" 
             headerClass="header"
             ... 
             rowClasses="odd-row,even-row">
   <h:column>
      <f:facet name="header">   
         <a href="?Sort=rank">Rank</a>
      </f:facet>
      <h:outputText value="#{company.rank}"/>
   </h:column>   
   <h:column>
      <f:facet name="header">   
         <a href="?Sort=name">Name</a>
      </f:facet>
      <h:outputText value="#{company.name}"/>
   </h:column>
   <h:column>
      <f:facet name="header">   
         <a href="?Sort=country">Country</a>
      </f:facet>
      <h:outputText value="#{company.country}"/>
   </h:column>
   <h:column>
      <f:facet name="header">   
          <a href="?Sort=category">Category</a>
      </f:facet>
      <h:outputText value="#{company.category}"/>
   </h:column>   
   <h:column>
      <f:facet name="header">   
         <a href="?Sort=sales">Sales</a>
      </f:facet>
      <h:outputText value="#{company.sales}">
         <f:convertNumber type="currency"/>
      </h:outputText>
   </h:column>   
... 
</h:dataTable>

 此外,我们要有一个filter,拦截所有请求,如果这个请求是要生成pdf的话,那么它的返回结果将会被flying saucer 解析并生成pdf.

public class RendererFilter implements Filter {
...
   public void doFilter(ServletRequest req, ServletResponse resp, 
                                    FilterChain filterChain) 
                                    throws IOException, ServletException {
      HttpServletRequest request = (HttpServletRequest)req;
      HttpServletResponse response = (HttpServletResponse)resp;
      //Check to see if this filter should apply.
      String renderType = request.getParameter("RenderOutputType");
      if(renderType != null) {
        //Capture the content for this request
        ContentCaptureServletResponse capContent = 
           new ContentCaptureServletResponse(response);  
        filterChain.doFilter(request,capContent);
          ...
        //Transform the XHTML content to a document 
        //readable by the renderer.
        StringReader contentReader = new StringReader(capContent.getContent());
        InputSource source = new InputSource(contentReader);
                Document xhtmlContent = documentBuilder.parse(source);
         ...
         }
        ...
  }
...
} 

 此外为了要去的response 返回的内容,我们要wrapper 一下response

public class ContentCaptureServletResponse 
                            extends HttpServletResponseWrapper {
   private ByteArrayOutputStream contentBuffer;
   private PrintWriter writer;
   public ContentCaptureServletResponse(HttpServletResponse resp) {
      super(resp); 
   }
   @Override
   public PrintWriter getWriter() throws IOException {
      if(writer == null){
         contentBuffer = new ByteArrayOutputStream();
         writer = new PrintWriter(contentBuffer);
      }
      return writer;
   }
   public String getContent(){
      writer.flush();
      String xhtmlContent = new String(contentBuffer.toByteArray());
      xhtmlContent = xhtmlContent.replaceAll("<thead>|</thead>|"+ 
                                             "<tbody>|</tbody>","");
      return xhtmlContent; 
   }
}

 下面的就是生成逻辑了,当然它也是在我们上面写的filter 中的

HttpServletResponse response = (HttpServletResponse)resp;
String renderType = request.getParameter("RenderOutputType");
...
StringReader contentReader = new StringReader(capContent.getContent());
InputSource source = new InputSource(contentReader);
Document xhtmlContent = documentBuilder.parse(source);
...
if(renderType.equals("pdf")){
   ITextRenderer renderer = new ITextRenderer();
   Renderer.setDocument(xhtmlContent,"");
   renderer.layout();
   response.setContentType("application/pdf");
   OutputStream browserStream = response.getOutputStream();
   renderer.createPDF(browserStream);
   return;
}

 大家可以看到,如果request 中的renderType等于pdf的话,我们就会调用itext跟flying saucer 的API把response 生成一个pdf.

大家可以看到上面这段生成pdf的逻辑非常简单, 是真正的write once , apply every where。 来再多的需求,我们只要create 相应的template(with CSS) 其余的生成逻辑全都一样。

希望这篇文章对跟我遇到相同问题的人有所帮助。

分享到:
评论

相关推荐

    flying-saucer生成pdf

    在使用flying-saucer生成PDF时,可能会遇到图片无法正确显示的情况。这通常与图片的路径、格式支持以及资源加载有关。确保图片URL是相对或绝对的正确路径,并且flying-saucer支持的图片格式(如JPEG、PNG、GIF)。...

    flying-saucer-pdf 生成pdf解决图片问题 解决中文问题

    在IT行业中,生成PDF文档是一项常见的任务,特别是在报告、手册或者网页内容转化为印刷格式时。`flying-saucer-pdf` 是一个强大的Java库,它允许开发者将HTML内容转换为高质量的PDF文档。这个库特别适合那些需要从...

    基于iText和flying saucer结合freemark生成pdf 范例

    基于iText和flying saucer结合freemark生成pdf 范例 1. 使用maven构建,不含jar包,可以自行使用maven下载依赖包, 2. 使用前需要将C:/Windows/Fonts/ARIALUNI.TTF 复制到doc-render/src/test/resources/config/fonts...

    SpringBoot集成Freemarker+FlyingSaucer实现pdf在线预览.pdf

    本文讲述如何使用SpringBoot集成Freemarker和FlyingSaucer实现PDF在线预览、打印和下载的功能。该技术方案可以应用于各种在线文档预览、报表生成、电子邮件发送等场景。 一、Freemarker模板引擎 Freemarker是Java...

    用flying saucer将html生成pdf的例子

    4. **PDF生成**:flying saucer生成的页面流通过iText处理,将其转换成符合PDF规范的文档。iText可以控制PDF的元数据、页面大小、安全设置等。 5. **输出与保存**:最后,生成的PDF文件可以被保存在本地、发送到...

    flyingsaucer转html为PDF(中文可用)

    4. **渲染到PDF**:最后,调用`renderer.layout`和`renderer.createPDF`方法生成PDF文件。例如: ```java renderer.layout(); FileOutputStream fos = new FileOutputStream("output.pdf"); renderer.createPDF...

    利用flying saucer 生成Pdf的例子

    本实例将深入探讨如何利用Flying Saucer生成PDF,并解决其中遇到的中文显示问题。 首先,Flying Saucer基于IText库,IText是一款强大的PDF处理工具,它提供了丰富的API用于创建、修改和处理PDF文档。Flying Saucer...

    flying-saucer-pdf-9.0.9转pdf相关包

    `flying-saucer`是一个流行的开源库,专门用于这个目的。标题中的“flying-saucer-pdf-9.0.9转pdf相关包”指的是使用`...同时,结合FreeMarker和iText,可以实现更复杂的功能,如动态生成PDF报告,满足各种定制化需求。

    flying saucer的中文不显示问题(修改源码后重新打的jar包)

    将这个新jar包集成到你的项目中,可以确保在使用Flying Saucer将网页转换为PDF时,中文内容能够正确显示。 总的来说,解决"Flying Saucer的中文不显示问题"是一个涉及字符编码配置和字体资源管理的过程。通过修改...

    flyingsaucer html转pdf demo

    Flyingsaucer的核心在于它使用了开源的Web渲染引擎IText,它能够解析HTML并将其转化为高质量的PDF文档。通过这个工具,我们可以将网页设计精确地复刻到PDF中,包括字体、颜色、图像、表格等元素。这为开发者提供了一...

    iText+Flying Saucer生成pdf文档所需要的jar包

    在“iText+Flying Saucer生成pdf文档jar包(修改后的)”这个描述中,"修改后的"可能指的是开发者对原始库进行了一些定制,以更好地支持中文显示。这可能包括修改字体设置、编码处理或者解决了某些特定的中文排版...

    flyingsaucer指导文档

    - **定义**: FlyingSaucer是一个用于渲染XML文档的开源项目,主要通过应用CSS样式来实现对文档内容的格式化。 - **作用**: 它可以将XML文档转换为适合屏幕显示(如在浏览器中查看)或打印输出(如生成PDF文件)的...

    Flying Saucer生成pdf文档jar包

    Flying Saucer生成pdf文档jar包 ,已做修改,支持中文 换行,但是 table标签换行 请改用CSS 样式:style="table-layout:fixed; word-break:break-strict;

    flying-saucer jar包下载

    Flying-Saucer在生成PDF时会依赖iText,用来处理PDF的具体细节,如字体、页眉页脚、书签等。 使用这些jar包,开发者可以通过以下步骤将HTML转换为PDF: 1. **初始化**: 首先,你需要导入所需的jar包,包括flying-...

    flying-saucer-pdf-9.0.3.jar

    基于iText 和 flying saucer结合freemark java 生成 pdf

    Flying-Saucer使用HTML或者FTL(Freemarker模板)生成PDF

    Flying-Saucer通过html生成pdf。。。项目中已经附带了jar包,放到项目中就可以运行了。亲测了,解决了中文不显示或者样式的问题,感觉蛮实用的。网上找了很久和下载其他资源用了好多积分,如果有需要的就下载吧!!...

    flyingsaucer-R8.zip

    《使用Flyingsaucer与iText生成PDF:技术解析与实践指南》 在现代的IT行业中,HTML到PDF的转换已经成为一种常见的需求,无论是为了打印、归档还是提供离线阅读,这种转换都能极大地提高效率。Flyingsaucer和iText...

    Flying Saucer实现html转pdf(一些问题,持续更新)

    `layout`方法布局HTML,然后`createPDF`方法生成PDF文件。 在实际应用中,你可能需要处理CSS以控制PDF的样式。Flying Saucer支持大部分CSS2属性,但不完全支持CSS3。比如,某些CSS3的布局特性如Flexbox和Grid在...

Global site tag (gtag.js) - Google Analytics