`

PDF生产方案 maven + freemarker + flyingSoaser 实现 附代码

 
阅读更多

        flyingSauser是一个非常好的生成PDF的开源项目,在文章中http://tommy-lu.iteye.com/admin/blogs/2224190也有提到,下面就使用 maven + freemarker + flyingSauser来搭建一个生成PDF的一个web项目。

    一、搭建maven项目

      使用过maven的人对这个应该不陌生,我这里是使用的是MyEclipse搭建maven项目,MyEclipse很好的集成了maven,使用起来非常的方便。在本例中我的项目名称是:flyingSauser-generatePDF,项目结构如下:



 

 

 

    二、编写初始化freemarker的类

       新建完毕项目之后,下面就开始干活了,这里我新建了一个类叫WrapFreemarkerHttpServlet,这个类主要就是用来实例化freemarker的Configuration,该类还集成了HttpServlet,这样如果我们的servlet的需要使用freemarker功能,只要继承这个类就可以了,然后子类只需要在init的方法里面调用super.init();方法即可,这样就达到了再servlet的生命周期里面只需要进行一次初始化freemarker。WrapFreemarkerHttpServlet类如下:

       

package com.cn.luqingyun.common;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

public class WrapFreemarkerHttpServlet extends HttpServlet {
	
	
	private static final long serialVersionUID = 1L;
	private Configuration cfg;
	
	public void init() throws ServletException {
		try {
			//获取模板所在文件夹参数,这个参数在web.xml里面配置。
			String freemarkerTemplatesFolder = this.getServletContext().getInitParameter("freemarkerTemplatesFolder");
			/* 在整个应用的生命周期中,这个工作你应该只做一次。 */
			/* 创建和调整配置。 */
			cfg = new Configuration(Configuration.getVersion());
			
			//获取模板文件夹路径
			String freemarkerTemplatesUrl = this.getServletContext().getRealPath("/" + freemarkerTemplatesFolder);
			
			//让freemarker从指定文件夹加载模板文件
			cfg.setDirectoryForTemplateLoading(new File(freemarkerTemplatesUrl));
			cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration
					.getVersion()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 输出数据到模板,子类只需要调用该方法,即可将数据输出到模板中
	 * @param templateFileName 模板名称
	 * @param root 数据模型
	 * @param os 
	 * @throws IOException 
	 * @throws ParseException 
	 * @throws MalformedTemplateNameException 
	 * @throws TemplateNotFoundException 
	 * @throws TemplateException 
	 */
	protected void process(String templateFileName, Map root,Writer os) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
		/* 获取或创建模板 */
		Template temp = cfg.getTemplate(templateFileName,"UTF-8");
		/* 将模板和数据模型合并 */
		// 注意:
		// 为了简单起见,这里压制了异常(在方法签名中声明了异常,译者注),而在正式运行的产品中不要这样做。;
		temp.process(root, os);
		os.flush();
	}
	

}

 

 

    三、编写生成PDF的servlet

        该类继承了WrapFreemarkerHttpServlet,在init()方法里面调用了super.init();主要就是初始化 freemarker,这个类有一行代码非常重要,fontResolver.addFont("fonts/simsun.ttc", BaseFont.IDENTITY_H,     BaseFont.NOT_EMBEDDED);这行代码是为了使flyingSauser支持中文,文件simsun.ttc需要放在类路径下面即可。该类的代码如下:

 

package com.cn.luqingyun.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xml.sax.SAXException;

import com.cn.luqingyun.common.WrapFreemarkerHttpServlet;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;

import freemarker.template.TemplateException;

/**
 * 注意这里继承的是WrapFreemarkerHttpServlet,该类除了具有HttpServlet的功能<br>
 * 还有初始化freemarker的功能
 * @author Tommy
 *
 */
public class PDFController extends WrapFreemarkerHttpServlet {

	private static final long serialVersionUID = 1L;

	public void init() throws ServletException {
		//初始化freemarker
		super.init();
	}

	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("application/pdf");

		try {
			// 1.freemarker处理

			// 创建数据模型
			Map root = new HashMap();
			root.put("user", "Flying Saucer介绍");
			root.put("text", "Flying Saucer is an XML/CSS renderer, which means it takes XML files as input, applies formatting and styling using CSS, and generates a rendered representation of that XML as output. The output may go to the screen (in a GUI), to an image, or to a PDF file. Because we believe most people will be interested in re-using their knowledge of web layout, our main target for content is XHTML 1.0 (strict), an XML document format that standardizes HTML.");

			// 指定模板文件,因为在web.xml中已经指定freemarker加载的文件夹 ,所以这里只需要指定文件名即可
			String templateFile = "pdfGenerate.ftl";

			// 输出到/WEB-INF/PDF/pdfFile.html
			String pdfFileUrl = getServletContext().getRealPath(
					"/WEB-INF/PDF/pdfFile.html");
			FileOutputStream fos = new FileOutputStream(new File(pdfFileUrl));
			Writer out = new OutputStreamWriter(fos, "UTF-8");

			// 将数据加载到模板文件
			process(templateFile, root, out);

			// 2.从freemarker产生的html文件生产PDF
			DocumentBuilder builder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			InputStream is = new FileInputStream(new File(pdfFileUrl));
			Document doc = builder.parse(is);
			ITextRenderer renderer = new ITextRenderer();

			// 解决中文支持问题
			ITextFontResolver fontResolver = renderer.getFontResolver();
			fontResolver.addFont("fonts/simsun.ttc", BaseFont.IDENTITY_H,
					BaseFont.NOT_EMBEDDED);
			
			renderer.setDocument(doc, null);
			renderer.layout();
			OutputStream os = response.getOutputStream();
			renderer.createPDF(os);
			os.close();

		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}

	}

}

         

   这里的模板文件的文件也非常简单,代码如下: 

 

<html>
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8"></meta>
		<title>flying sauser</title>
                <!--加这行代码的原因是,因为flyingSauser需要中文支持就必须要加,具体原因还不太清楚-->
		<style type="text/css">
			body {  
	         	font-family: SimSun;  
	     	}  
		</style>
	</head>
	<body>
		<h1>
			${user}
		</h1>
		<p style="text-indent: 2em;">
			${text}
		</p>
	</body>
</html>

 

     

    四、实现效果

     


 
 

   

     注意事项:编写模板的时候一定要有结束标签,例如<meta http-equiv="content-type" content="text/html; charset=UTF-8"></meta>这一行代码不能写成<meta http-equiv="content-type" content="text/html; charset=UTF-8">否则会报The element type "meta" must be terminated by the matching end-tag "</meta>".

      需要完整项目的可以在评论区里面提供QQ号。很少写博客,有不足之处请多多之处,附件中提供了几个使用到的类,以及web.xml、simsun.ttc 以及pom.xml。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics