项目上的客户提出一个需求,把政务流程中的表单数据导出成pdf或者图片格式,用来作电子档案材料。表单基于公司的电子政务构建平台实现,在数据库保存的都是html格式,因此打算直接把表单html转成pdf或者图片。由于表单是已经写好了html页面,那我要做的就是能完美解析html+css的pdf生成工具。在百度上搜索html转pdf的结果,大部分都是用itext,itext的确是Java开源组件的第一选择。不过itext也有局限,就是要自己写模版,系统中的表单数量有好几百个,为每个表单做一个导出模版不现实。
最后,wkhtmltopdf进入了我的选择范围。wkhtmltopdf是一个使用webkit网页渲染引擎开发的用来将 html转成 pdf的工具,可以跟多种脚本语言进行集成来转换文档。
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工具类,方便调用。
- importjava.io.File;
- publicclassHtmlToPdf{
- //wkhtmltopdf在系统中的路径
- privatestaticfinalStringtoPdfTool="c:\\wkhtmltopdf.exe";
- /**
- *html转pdf
- *@paramsrcPathhtml路径,可以是硬盘上的路径,也可以是网络路径
- *@paramdestPathpdf保存路径
- *@return转换成功返回true
- */
- publicstaticbooleanconvert(StringsrcPath,StringdestPath){
- Filefile=newFile(destPath);
- Fileparent=file.getParentFile();
- //如果pdf保存路径不存在,则创建路径
- if(!parent.exists()){
- parent.mkdirs();
- }
- StringBuildercmd=newStringBuilder();
- cmd.append(toPdfTool);
- cmd.append("");
- cmd.append(srcPath);
- cmd.append("");
- cmd.append(destPath);
- booleanresult=true;
- try{
- Processproc=Runtime.getRuntime().exec(cmd.toString());
- HtmlToPdfInterceptorerror=newHtmlToPdfInterceptor(proc.getErrorStream());
- HtmlToPdfInterceptoroutput=newHtmlToPdfInterceptor(proc.getInputStream());
- error.start();
- output.start();
- proc.waitFor();
- }catch(Exceptione){
- result=false;
- e.printStackTrace();
- }
- returnresult;
- }
- }
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中有这种现象)。
- importjava.io.BufferedReader;
- importjava.io.IOException;
- importjava.io.InputStream;
- importjava.io.InputStreamReader;
- /**
- *当java调用wkhtmltopdf时,用于获取wkhtmltopdf返回的内容
- */
- publicclassHtmlToPdfInterceptorextendsThread{
- privateInputStreamis;
- publicHtmlToPdfInterceptor(InputStreamis){
- this.is=is;
- }
- publicvoidrun(){
- try{
- InputStreamReaderisr=newInputStreamReader(is,"utf-8");
- BufferedReaderbr=newBufferedReader(isr);
- Stringline=null;
- while((line=br.readLine())!=null){
- System.outlprintln(line.toString());//输出内容
- }
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- }
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中调用
- /**
- *Html转PDF
- */
- @WebServlet("/htmltopdf/servlet")
- publicclassHtmlToPdfServletextendsHttpServlet{
- privatestaticfinallongserialVersionUID=1L;
- /**
- *Servlet接收参数path,获取html的url
- */
- protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
- Stringpath=request.getParameter("path");
- if(path==null||path.equals("")){
- return;
- }
- //获取pdf的临时保存路径
- //tmp为网站下的目录
- //把生成的pdf放到网站下以便下载
- StringpdfPath=request.getSession().getServletContext().getRealPath("/tmp");
- StringpdfName=UUID.randomUUID().toString()+".pdf";
- if(HtmlToPdf.convert(path,pdfPath+"/"+pdfName)){
- response.sendRedirect(request.getContextPath()+"/tmp/"+pdfName);
- }
- }
- }
/**
* 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