最近产品开发遇到一个比较棘手的问题,我们产品的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解决大部分的问题 1.图片显示问题 2.中文显示问题,css样式问题 3.表格跨行问题
flying-saucer-pdf 生成pdf解决图片问题 解决中文问题
基于iText和flying saucer结合freemark生成pdf 范例 1. 使用maven构建,不含jar包,可以自行使用maven下载依赖包, 2. 使用前需要将C:/Windows/Fonts/ARIALUNI.TTF 复制到doc-render/src/test/resources/config/fonts...
本资源是自己在利用itext和flying saucer将html生成pdf,并使用freemarker模板引擎的样例
Flying Saucer生成pdf文档jar包 ,已做修改,支持中文 换行,但是 table标签换行 请改用CSS 样式:style="table-layout:fixed; word-break:break-strict;
使用flyingsaucer将网页转换为pdf之中文问题彻底解决
基于iText 和 flying saucer结合freemark java 生成 pdf
实例介绍,包含中文问题的解决方法等,在生成pdf的过程中遇到的问题。希望对大家又算帮助
iText+Flying Saucer生成pdf文档jar包(修改后的)支持中文
Flying-Saucer通过html生成pdf。。。项目中已经附带了jar包,放到项目中就可以运行了。亲测了,解决了中文不显示或者样式的问题,感觉蛮实用的。网上找了很久和下载其他资源用了好多积分,如果有需要的就下载吧!!...
flying-saucer-coreR-9.0.7 中修改Breaker类,解决PDF中文没有对齐问题。
flying sauser,基于iText自身的问题,让我们开始寻求可以真正意义上模版技术,那么flying sauser就是为了这个问题出现的产品,能解析HTML和CSS,而且能输出成image,PDF等格式。具体使用,请访问:...
NULL 博文链接:https://cuiyaoonan2000.iteye.com/blog/2173135
Flying Saucer(或者叫xhtmlrender project on java.net)是一个基于iText的开源java库,能够轻松的将html(带css2.1)生成pdf。 网站:http://code.google.com/p/flying-saucer/ 基于这个两个技术,大致就有了以下思路...
Flying Saucer 实现html 生成pdf 代码可以参照我的博客
iText+Flying Saucer生成pdf文档,中文不显示和不自动换行问题重新Breaker.class
一个很好用的工具,可以将HTML直接转成PDF文件,包括PDF的字体、PDF的格式、Image如何处理等等,结合freemarker模板可以很好的做到PDF文件的导出。
NULL 博文链接:https://u010650064.iteye.com/blog/2178435
1.html模板+model数据,通过freemarker进行渲染,便于维护和修改 2.渲染后的html流,可通过Flying Saucer组件生成pdf文件流,或者生成pdf后再转成jpg文件流
可以在freemaker生成pdf时,解决中文不能换行的问题