Java实现Html转PDF

项目上的客户提出一个需求,把政务流程中的表单数据导出成pdf或者图片格式,用来作电子档案材料。表单基于公司的电子政务构建平台实现,在数据库保存的都是html格式,因此打算直接把表单html转成pdf或者图片。由于表单是已经写好了html页面,那我要做的就是能完美解析html+css的pdf生成工具。在百度上搜索html转pdf的结果,大部分都是用itext,itext的确是Java开源组件的第一选择。不过itext也有局限,就是要自己写模版,系统中的表单数量有好几百个,为每个表单做一个导出模版不现实。

最后,wkhtmltopdf进入了我的选择范围。wkhtmltopdf是一个使用webkit网页渲染引擎开发的用来将 html转成 pdf的工具,可以跟多种脚本语言进行集成来转换文档。

官网地址 http://wkhtmltopdf.org/

github地址 https://github.com/wkhtmltopdf/wkhtmltopdf

wkhtmltopdf把html转成pdf很简单,只要在windows命令行中输入

c:\wkhtmltopdf.exe http://www.csdn.NET c:\csdn.pdf

就可以把csdn网页转成pdf,并保存到C盘根目录。

在java中调用wkhtmltopdf的命令Runtime.getRuntime().exec("c:\wkhtmltopdf.exe http://www.csdn.Net c:\csdn.pdf")就可以实现转换。

下面把命令封装成java工具类,方便调用。

[java] view plain copy
print ?
  1. importjava.io.File;
  2. publicclassHtmlToPdf{
  3. //wkhtmltopdf在系统中的路径
  4. privatestaticfinalStringtoPdfTool="c:\\wkhtmltopdf.exe";
  5. /**
  6. *html转pdf
  7. *@paramsrcPathhtml路径,可以是硬盘上的路径,也可以是网络路径
  8. *@paramdestPathpdf保存路径
  9. *@return转换成功返回true
  10. */
  11. publicstaticbooleanconvert(StringsrcPath,StringdestPath){
  12. Filefile=newFile(destPath);
  13. Fileparent=file.getParentFile();
  14. //如果pdf保存路径不存在,则创建路径
  15. if(!parent.exists()){
  16. parent.mkdirs();
  17. }
  18. StringBuildercmd=newStringBuilder();
  19. cmd.append(toPdfTool);
  20. cmd.append("");
  21. cmd.append(srcPath);
  22. cmd.append("");
  23. cmd.append(destPath);
  24. booleanresult=true;
  25. try{
  26. Processproc=Runtime.getRuntime().exec(cmd.toString());
  27. HtmlToPdfInterceptorerror=newHtmlToPdfInterceptor(proc.getErrorStream());
  28. HtmlToPdfInterceptoroutput=newHtmlToPdfInterceptor(proc.getInputStream());
  29. error.start();
  30. output.start();
  31. proc.waitFor();
  32. }catch(Exceptione){
  33. result=false;
  34. e.printStackTrace();
  35. }
  36. returnresult;
  37. }
  38. }
import java.io.File;

public class HtmlToPdf {
	//wkhtmltopdf在系统中的路径
	private static final String toPdfTool = "c:\\wkhtmltopdf.exe";
	
	/**
	 * html转pdf
	 * @param srcPath html路径,可以是硬盘上的路径,也可以是网络路径
	 * @param destPath pdf保存路径
	 * @return 转换成功返回true
	 */
	public static boolean convert(String srcPath, String destPath){
		File file = new File(destPath);
		File parent = file.getParentFile();
		//如果pdf保存路径不存在,则创建路径
		if(!parent.exists()){
			parent.mkdirs();
		}
		
		StringBuilder cmd = new StringBuilder();
		cmd.append(toPdfTool);
		cmd.append(" ");
		cmd.append(srcPath);
		cmd.append(" ");
		cmd.append(destPath);
		
		boolean result = true;
		try{
			Process proc = Runtime.getRuntime().exec(cmd.toString());
			HtmlToPdfInterceptor error = new HtmlToPdfInterceptor(proc.getErrorStream());
			HtmlToPdfInterceptor output = new HtmlToPdfInterceptor(proc.getInputStream());
			error.start();
			output.start();
			proc.waitFor();
		}catch(Exception e){
			result = false;
			e.printStackTrace();
		}
		
		return result;
	}
}

接收Process的输入和错误信息时,需要创建另外的线程,否则当前线程会一直等待(在Tomcat中有这种现象)。

[java] view plain copy
print ?
  1. importjava.io.BufferedReader;
  2. importjava.io.IOException;
  3. importjava.io.InputStream;
  4. importjava.io.InputStreamReader;
  5. /**
  6. *当java调用wkhtmltopdf时,用于获取wkhtmltopdf返回的内容
  7. */
  8. publicclassHtmlToPdfInterceptorextendsThread{
  9. privateInputStreamis;
  10. publicHtmlToPdfInterceptor(InputStreamis){
  11. this.is=is;
  12. }
  13. publicvoidrun(){
  14. try{
  15. InputStreamReaderisr=newInputStreamReader(is,"utf-8");
  16. BufferedReaderbr=newBufferedReader(isr);
  17. Stringline=null;
  18. while((line=br.readLine())!=null){
  19. System.outlprintln(line.toString());//输出内容
  20. }
  21. }catch(IOExceptione){
  22. e.printStackTrace();
  23. }
  24. }
  25. }
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 当java调用wkhtmltopdf时,用于获取wkhtmltopdf返回的内容
 */
public class HtmlToPdfInterceptor extends Thread {
	private InputStream is;
	
	public HtmlToPdfInterceptor(InputStream is){
		this.is = is;
	}
	
	public void run(){
		try{
			InputStreamReader isr = new InputStreamReader(is, "utf-8");
			BufferedReader br = new BufferedReader(isr);
			String line = null;
			while ((line = br.readLine()) != null) {
				System.outlprintln(line.toString()); //输出内容
			}
		}catch (IOException e){
			e.printStackTrace();
		}
	}
}

在Servlet中调用

[java] view plain copy
print ?
  1. /**
  2. *Html转PDF
  3. */
  4. @WebServlet("/htmltopdf/servlet")
  5. publicclassHtmlToPdfServletextendsHttpServlet{
  6. privatestaticfinallongserialVersionUID=1L;
  7. /**
  8. *Servlet接收参数path,获取html的url
  9. */
  10. protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
  11. Stringpath=request.getParameter("path");
  12. if(path==null||path.equals("")){
  13. return;
  14. }
  15. //获取pdf的临时保存路径
  16. //tmp为网站下的目录
  17. //把生成的pdf放到网站下以便下载
  18. StringpdfPath=request.getSession().getServletContext().getRealPath("/tmp");
  19. StringpdfName=UUID.randomUUID().toString()+".pdf";
  20. if(HtmlToPdf.convert(path,pdfPath+"/"+pdfName)){
  21. response.sendRedirect(request.getContextPath()+"/tmp/"+pdfName);
  22. }
  23. }
  24. }
/**
 * Html转PDF
 */
@WebServlet("/htmltopdf/servlet")
public class HtmlToPdfServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	/**
	 * Servlet接收参数path,获取html的url
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String path = request.getParameter("path");
		if(path == null || path.equals("")){
			return;
		}
		
		//获取pdf的临时保存路径
		//tmp为网站下的目录
		//把生成的pdf放到网站下以便下载
		String pdfPath = request.getSession().getServletContext().getRealPath("/tmp");
		String pdfName = UUID.randomUUID().toString() + ".pdf";
		
		if(HtmlToPdf.convert(path, pdfPath + "/" + pdfName)){
			response.sendRedirect(request.getContextPath() + "/tmp/" + pdfName);
		}
	}
}

在浏览器中输入http://<网站路径>/htmltopdf/servlet?path=http://blog.csdn.net


你可能感兴趣的:(Java实现Html转PDF)