Freemarker+Flying sauser +Itext 整合生成PDF

原文地址:http://jeemiss.iteye.com/blog/1112765

参考资料:http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html


Freemarker、Flying sauser 、Itext ,这三个框架的作用就不详细介绍了,google一下就知道了。

Itext提供了很多底层的API,让我们可以用java代码画一个pdf出来,但是很不灵活,布局渲染代码都hard code 进java类里面了。

当需求发生改变时,哪怕只需要更改一个属性名,我们都要重新修改那段代码,很不符合开放关闭的原则。想到用模版来做渲染,但自己实现起来比较繁琐,然后google了下,找到了用freemarker做模版,Flying sauser 照着模版做渲染,让Itext做输出生成PDF的方案。

 

   freemarker和itext都比较熟悉了,Flying sauser 第一次听说,看完官方的user guide(http://flyingsaucerproject.github.com/flyingsaucer/r8/guide/users-guide-R8.html)后,自己着手做了个demo实践:


需要的包:core-renderer.jar   和  iText-2.0.8.jar

 

    Freemarker+Flying sauser +Itext 整合生成PDF_第1张图片

    测试数据模型:

package com.jeemiss.pdfsimple.entity;

public class User {
	
	private String name;
	private int age;
	private int sex;
	
	/**
	 * Constructor with all fields
	 * 
	 * @param name
	 * @param age
	 * @param sex
	 */
	public User(String name, int age, int sex) {
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	
	///////////////////////   getter and setter   ///////////////////////////////////////////
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getSex() {
		return sex;
	}
	public void setSex(int sex) {
		this.sex = sex;
	}
	
	

}

 

模板文件配置

package com.jeemiss.pdfsimple.freemarker;

import freemarker.template.Configuration;

public class FreemarkerConfiguration {
	
	private static Configuration config = null;
	
	/**
	 * Static initialization.
	 * 
	 * Initialize the configuration of Freemarker.
	 */
	static{
		config = new Configuration();
		config.setClassForTemplateLoading(FreemarkerConfiguration.class, "template");
	}
	
	public static Configuration getConfiguation(){
		return config;
	}

}

 

 HTML生成器:

package com.jeemiss.pdfsimple.generator;

import java.io.BufferedWriter;
import java.io.StringWriter;
import java.util.Map;
import com.jeemiss.pdfsimple.freemarker.FreemarkerConfiguration;
import freemarker.template.Configuration;
import freemarker.template.Template;

public class HtmlGenerator {
	
	/**
	 * Generate html string.
	 * 
	 * @param template   the name of freemarker teamlate.
	 * @param variables  the data of teamlate.
	 * @return htmlStr
	 * @throws Exception
	 */
	public static String generate(String template, Map<String,Object> variables) throws Exception{
		Configuration config = FreemarkerConfiguration.getConfiguation();
		Template tp = config.getTemplate(template);
		StringWriter stringWriter = new StringWriter();  
		BufferedWriter writer = new BufferedWriter(stringWriter);  
		tp.setEncoding("UTF-8");  
		tp.process(variables, writer);  
		String htmlStr = stringWriter.toString();
		writer.flush();  
		writer.close();
		return htmlStr;
	}

}

   PDF 生成器:

package com.jeemiss.pdfsimple.generator;

import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;

public class PdfGenerator {

	/**
	 * Output a pdf to the specified outputstream
	 * 
	 * @param htmlStr the htmlstr
	 * @param out the specified outputstream
	 * @throws Exception
	 */
	public static void generate(String htmlStr, OutputStream out)
			throws Exception {
		DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document doc = builder.parse(new ByteArrayInputStream(htmlStr.getBytes()));
		ITextRenderer renderer = new ITextRenderer();
		renderer.setDocument(doc, null);
		renderer.layout();
		renderer.createPDF(out);
		out.close();
	}

}


 

    用来做测试的ftl模版,用到部分css3.0的属性来控制pdf强制分页和输出分页信息

HTML代码:
<html>
<head>
  <title>${title}</title>
  <style>
     table {
    		 width:100%;border:green dotted ;border-width:2 0 0 2
     }
     td {
    		 border:green dotted;border-width:0 2 2 0
     }
     @page {  
              size: 8.5in 11in; 
              @bottom-center {
    				content: "page " counter(page) " of  " counter(pages);
  			  }
     }
  </style>
</head>
<body>
  <h1>Just a blank page.</h1>
  <div style="page-break-before:always;">
      <div align="center">
	      <h1>${title}</h1>
	  </div>
	  <table>
	     <tr>
	        <td><b>Name</b></td>
	        <td><b>Age</b></td>
	        <td><b>Sex</b></td>
	     </tr>
	     <#list userList as user>
	        <tr>
		        <td>${user.name}</td>
		        <td>${user.age}</td>
		        <td>
		           <#if user.sex = 1>
		             	 male
		           <#else>
		              	 female
		           </#if>
		        </td>
	        </tr>
	     </#list>
	  </table>
  </div>
</body>
</html> 

最后写个测试用例看看:

package com.jeemiss.pdfsimple.test;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.jeemiss.pdfsimple.entity.User;
import com.jeemiss.pdfsimple.generator.HtmlGenerator;
import com.jeemiss.pdfsimple.generator.PdfGenerator;

public class TestCase 
{
   @Test
   public void generatePDF() {
	   try{
		   String outputFile = "C:\\sample.pdf";
		   Map<String,Object> variables = new HashMap<String,Object>();
		    
		   List<User> userList = new ArrayList<User>();
		   
		   User tom = new User("Tom",19,1);
		   User amy = new User("Amy",28,0);
		   User leo = new User("Leo",23,1);
		   
		   userList.add(tom);
		   userList.add(amy);
		   userList.add(leo);
		   
		   variables.put("title", "User List");
		   variables.put("userList", userList);
		  
		   String htmlStr = HtmlGenerator.generate("sample.ftl", variables);
		   
		   OutputStream out = new FileOutputStream(outputFile);
		   PdfGenerator.generate(htmlStr, out);
		   
	   }catch(Exception ex){
		   ex.printStackTrace();
	   }
	   
   }
}


若要在Web中实现点击某个下载PDF按钮后,浏览器出现下载框的话,只要将 输出流做如下处理:

response.setHeader("Content-disposition", "attachment; filename="
				     + new String("YourPdfName.pdf".getBytes("gb2312"), "iso8859-1"));
response.setContentType("application/pdf");
			
OutputStream out = response.getOutputStream();

//将PDF写入此输出流

最后记得将流关闭
out.flush();
out.close();

 不过,如上方法并不支持中文,如要支持中文,可以在创建PDF的方法内加入如下方法(未验证是否可行) 
 

......
......
renderer.setDocument(doc, null); 

// 解决中文支持问题  
  ITextFontResolver fontResolver = renderer.getFontResolver();  
  fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);  
  
 // 解决图片的相对路径问题  
 renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");

renderer.layout(); 
renderer.createPDF(out);
......
......



你可能感兴趣的:(freemarker,freemarker,freemarker,itext,itext,itext,Flying,生成PDF,sauser)