?flying saucer技術生成pdf文檔的實現代碼:
Servlet方式:
html代碼:
[html] view plaincopyprint?
< %@?page?language ="java" ?import ="java.util.*" ?pageEncoding ="ISO-8859-1" %> ??< %??String?path ?=?request .getContextPath();?? String?basePath ?=?request .getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";?? %> ?? ?? <!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN"> ?? < html > ????< head > ?? ????< base ?href ="<%=basePath%>" > ?? ?????? ????< title > Html2PdfServlet</ title > ?? ????< meta ?http-equiv ="pragma" ?content ="no-cache" > ?? ????< meta ?http-equiv ="cache-control" ?content ="no-cache" > ?? ????< meta ?http-equiv ="expires" ?content ="0" > ?????? ????< meta ?http-equiv ="keywords" ?content ="keyword1,keyword2,keyword3" > ?? ????< meta ?http-equiv ="description" ?content ="This?is?my?page" > ?? ????? ? ?? ??</ head > ?? ???? ??< body > ?? ????< form ?action ="http://localhost:8081/createpdf/servlet/html2PdfServlet" ?method ="get" ?> ?? ????< table > ?? ????????< tr > ?? ????????????< td > ?? ????????????????< input ?type ="text" ?id ="username" ?name ="username" ?value ="" ?/> ?? ????????????</ td > ?? ????????????< td > ?? ????????????????< input ?type ="submit" ?id ="submit" ?name ="submit" ?value ="submit" ?/> ?? ????????????</ td > ?? ????????</ tr > ?? ????</ table > ?? ????</ form > ?? ??</ body > ?? </ html > ??
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>Html2PdfServlet</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--></head><body><form action="http://localhost:8081/createpdf/servlet/html2PdfServlet" method="get" ><table><tr><td><input type="text" id="username" name="username" value="" /></td><td><input type="submit" id="submit" name="submit" value="submit" /></td></tr></table></form></body>
</html>
?
java代碼:
[java] view plaincopyprint?
package ?com.test;???? import ?java.io.IOException;??import ?java.io.OutputStream;???? import ?javax.servlet.ServletContext;??import ?javax.servlet.ServletException;??import ?javax.servlet.http.HttpServlet;??import ?javax.servlet.http.HttpServletRequest;??import ?javax.servlet.http.HttpServletResponse;???? import ?org.xhtmlrenderer.pdf.ITextFontResolver;??import ?org.xhtmlrenderer.pdf.ITextRenderer;???? import ?com.lowagie.text.pdf.BaseFont;???? public ?class ?Html2PdfServlet?extends ?HttpServlet?{???? ????private ?static ?final ?long ?serialVersionUID?=?1L;?? ?? ????public ?void ?doGet(HttpServletRequest?request,?HttpServletResponse?response)?? ????????throws ?ServletException,?IOException?{?? ?????????? ????????ServletContext?sc?=?request.getSession().getServletContext();?? ????????String?path?=?sc.getRealPath("" );??? ????????System.out.println("原path:?" ?+?path);?? ???????? ?? ????????path?=?path.replaceAll("\\\\",?" /");??? ????????System.out.println(path);?? ?????????? ????????String?path2?=?sc.getRealPath("/" );?? ????????System.out.println("path2:?" ?+?path2);?? ?????????? ????????System.out.println(Thread.currentThread().getContextClassLoader().getResource("" ));?? ?????????? ????????System.out.println("request.getRequestURI:?" ?+?request.getRequestURI());?? ?????????? ????????System.out.println(request.getLocalPort());?? ?????????? ????????String?path3?=?request.getContextPath();?? ????????String?basePath?=?request.getScheme()+"://" +request.getServerName()+":" +request.getServerPort()+path3+"/" ;?? ?????????? ????????System.out.println("basepath:?" ?+?basePath);?? ?????????? ?????????? ????????response.setContentType("application/pdf" );?? ?????????? ????????response.setHeader("Content-Disposition" ,?"inline;?filename=WebReport.pdf" );?? ?????????? ????????StringBuffer?html?=?new ?StringBuffer();?? ?????????? ????????html.append("<!DOCTYPE?html?PUBLIC?\"-//W3C//DTD?XHTML?1.0?Transitional//EN\"?\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" );?? ????????html.append("<html?xmlns=\"http://www.w3.org/1999/xhtml\">" )?? ????????.append("<head>" )?? ????????.append("<meta?http-equiv=\"Content-Type\"?content=\"text/html;?charset=UTF-8\"?/>" )?? ????????.append("<style?type=\"text/css\"?mce_bogus=\"1\">body?{font-family:?SimSun;}</style>" )?? ????????.append("<style?type=\"text/css\">img?{width:?700px;}</style>" )?? ????????.append("</head>" )?? ????????.append("<body>" );?? ?????????? ????????html.append("<center><h1>統計報表</h1></center>" );?? ????????html.append("<center>" );?? ????????html.append("<img?src=\"images/chart.jpg\"/>" );?? ????????html.append("</center>" );?? ?????????? ????????html.append("</body></html>" );?? ?????????? ?????????? ????????try ?{?? ????????????ITextRenderer?renderer?=?new ?ITextRenderer();?? ????????????? ? ? ? ? ?? ????????????renderer.setDocumentFromString(html.toString());?? ?????????????? ?????????????? ?????????????? ????????????renderer.getSharedContext().setBaseURL("file:/" ?+?path?+?"/images" );?? ????????????renderer.layout();?? ????????????OutputStream?os?=?response.getOutputStream();?? ????????????renderer.createPDF(os);?? ????????????os.close();?? ????????}?catch ?(Exception?e)?{?? ????????????e.printStackTrace();?? ????????}?? ?? ????}?? ?? ????public ?void ?doPost(HttpServletRequest?request,?HttpServletResponse?response)?? ????????????throws ?ServletException,?IOException?{?? ????????doGet(request,?response);?? ????}?? ?? }??
package com.test;import java.io.IOException;
import java.io.OutputStream;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import com.lowagie.text.pdf.BaseFont;public class Html2PdfServlet extends HttpServlet {private static final long serialVersionUID = 1L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//pageContext.getServletContext().getRealPath("/")ServletContext sc = request.getSession().getServletContext();String path = sc.getRealPath(""); //值為D:\apache-tomcat-6.0.26\webapps\createpdfSystem.out.println("原path: " + path);//把路徑中的反斜杠轉成正斜杠path = path.replaceAll("\\\\", "/"); //值為D:/apache-tomcat-6.0.26/webapps/createpdfSystem.out.println(path);String path2 = sc.getRealPath("/");System.out.println("path2: " + path2);System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));System.out.println("request.getRequestURI: " + request.getRequestURI());//獲取使用的端口號System.out.println(request.getLocalPort());String path3 = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path3+"/";System.out.println("basepath: " + basePath);response.setContentType("application/pdf");//response.setHeader("Content-Disposition", "attachment; filename=WebReport.pdf");response.setHeader("Content-Disposition", "inline; filename=WebReport.pdf");StringBuffer html = new StringBuffer();//組裝成符合W3C標準的html文件,否則不能正確解析html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">").append("<head>").append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />").append("<style type=\"text/css\" mce_bogus=\"1\">body {font-family: SimSun;}</style>").append("<style type=\"text/css\">img {width: 700px;}</style>").append("</head>").append("<body>");html.append("<center><h1>統計報表</h1></center>");html.append("<center>");html.append("<img src=\"images/chart.jpg\"/>");html.append("</center>");html.append("</body></html>");// parse our markup into an xml Documenttry {ITextRenderer renderer = new ITextRenderer();/*** 引入了新的jar包,不用再導入字體了ITextFontResolver fontResolver = renderer.getFontResolver();fontResolver.addFont("C:/Windows/fonts/simsun.ttc",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);*/renderer.setDocumentFromString(html.toString());// 解決圖片的相對路徑問題//renderer.getSharedContext().setBaseURL("file:/C:/Documents and Settings/dashan.yin/workspace/createpdf/WebRoot/images");//renderer.getSharedContext().setBaseURL("file:/D:/apache-tomcat-6.0.26/webapps/createpdf/images");renderer.getSharedContext().setBaseURL("file:/" + path + "/images");renderer.layout();OutputStream os = response.getOutputStream();renderer.createPDF(os);os.close();} catch (Exception e) {e.printStackTrace();}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
Struts1形式:
html代碼:
[html] view plaincopyprint?
< %@?page?language ="java" ?import ="java.util.*" ?pageEncoding ="UTF-8" %> ??< %@?page?import ="Config.application.*" ?%> ??< %@?include?file ="/pages/common/global.jsp" ?%> ??< %@?taglib?uri ="/WEB-INF/tlds/birt.tld" ?prefix ="birt" %> ??< script ?type ="text/javascript" > ??????function?interactivity()?{?? ????????var?url ?=?contextName ?+?"/viewAction.do?method =viewLinkResult ";?? ????????var?startDate_s ?=?$("#startDate_s").val();?? ????????var?endDate_s ?=?$("#endDate_s").val();?? ????????var?serviceInstance ?=?$("#serviceInstance").val();?? ????????var?serviceInstance ?=?encodeURIComponent (serviceInstance);?? ????????var?status ?=?$("#status").val();?? ????????if(startDate_s){?? ????????????url?+=?"&startDate_s ="?+?startDate_s;?? ????????}?? ????????if(endDate_s){?? ????????????url?+=?"&endDate_s ="?+?endDate_s;?? ????????}?? ????????if(serviceInstance){?? ????????????url?+=?"&serviceInstance ="?+?serviceInstance;?? ????????}?? ????????if(status){?? ????????????url?+=?"&status ="?+?status;?? ????????}?? ????????url?+=?"&random ="?+?Math.random();?? ????????//alert(url);?? ????????retrieveURL(url,'viewResult');?? ????????//tipsWindown("詳細信息","url:get?"?+?url,"800","700","true","","true","text");?? ????}?? ?????? ?????? ????function?viewreturn()?{?? ????????var?url ?=?contextName ?+?"/viewAction.do?method =viewReturnResult ";?? ????????//時間參數設空?? ????????document.getElementById("startDate_s").value ?=?"" ;?? ????????document.getElementById("endDate_s").value ?=?"" ;?? ????????url?+=?"&random ="?+?Math.random();?? ????????retrieveURL(url,'viewResult');?? ????????//tipsWindown("詳細信息","url:get?"?+?url,"800","700","true","","true","text");?? ????}?? ?????? </ script > ???? < html:form ?action ="/viewAction.do?method=viewExportPDF" > ??????< table ?class ="form_t" ?style ="width:100%" > ?? ????????< tr > ?? ????????????< td > ?? ????????????????< input ?type ="submit" ?id ="submit" ?name ="submit" ?value ="導出" ?class ="button4C" /> ?? ????????????</ td > ?? ????????</ tr > ?? ????</ table > ?? </ html:form > ??< html:form ?action ="/viewAction.do?method=viewResult" ??> ??????< table ?class ="form_t" ?style ="width:100%" > ?? ????????< tr > ?? ????????????< th ?class ="tablelogo" ?colspan ="3" > ?? ????????????????統計時間?? ????????????</ th > ?? ?????????????? ????????</ tr > ?? ????????????< tr > ?? ????????????????< td ?style ="width:?175px;?text-align:?right;" > ?? ????????????????????開始時間?? ????????????????</ td > ?? ????????????????< td > ??? ????????????????????< input ?type ="text" ?name ="startDate_s" ?id ="startDate_s" ?? ????????????????????????class ="Wdate" ?? ????????????????????????onclick ="WdatePicker({dateFmt:'yyyy-MM-dd?HH:mm:ss',maxDate:'#F{$dp.$D(\'endDate_s\')||\'%y-%M-%d?%H:{%m-1}:%s\'}'})" ?/> ?? ????????????????</ td > ?? ????????????????< td > ?? ??????????????????????? ????????????????????< input ?type ="hidden" ?name ="serviceInstance" ?id ="serviceInstance" ?value ="" /> ?? ????????????????????< input ?type ="hidden" ?name ="status" ?id ="status" ?value ="" /> ?? ????????????????</ td > ?? ????????????</ tr > ?? ????????????< tr > ?? ????????????????< td ?style ="width:?175px;?text-align:?right;" > ?? ????????????????????結束時間?? ????????????????</ td > ?? ????????????????< td > ??? ????????????????????< input ?type ="text" ?name ="endDate_s" ?id ="endDate_s" ?class ="Wdate" ?? ????????????????????????onclick ="WdatePicker({dateFmt:'yyyy-MM-dd?HH:mm:ss',minDate:'#F{$dp.$D(\'startDate_s\')}',maxDate:'%y-%M-%d?%H:%m:%s'})" ?/> ?? ????????????????</ td > ?? ????????????????< td > ?? ??????????????????????? ????????????????</ td > ?? ????????????</ tr > ?? ????????< tr > ?? ????????????< td ?style ="padding-left:?175px;" ?colspan ="2" > ?? ????????????????< input ?type ="button" ?value ="查看" ?class ="button4C" ?? ????????????????????onclick ="javascript:viewForm(this.form,'viewResult');" ?/> ?? ????????????????< input ?type ="button" ?value ="返回" ?class ="button4C" ?? ????????????????????onclick ="javascript:viewreturn();" ?/> ?? ????????????</ td > ?? ????????????< td > ??? ????????????</ td > ?? ????????</ tr > ?? ????</ table > ?? </ html:form > ??< table ?width ="100%" > ??????< tr > ?? ????????< td ?id ="viewResult" ?width ="100%" > </ td > ?? ????</ tr > ?? </ table > ??
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="Config.application.*" %>
<%@ include file="/pages/common/global.jsp" %>
<%@ taglib uri="/WEB-INF/tlds/birt.tld" prefix="birt"%>
<script type="text/javascript">function interactivity() {var url = contextName + "/viewAction.do?method=viewLinkResult";var startDate_s = $("#startDate_s").val();var endDate_s = $("#endDate_s").val();var serviceInstance = $("#serviceInstance").val();var serviceInstance = encodeURIComponent(serviceInstance);var status = $("#status").val();if(startDate_s){url += "&startDate_s=" + startDate_s;}if(endDate_s){url += "&endDate_s=" + endDate_s;}if(serviceInstance){url += "&serviceInstance=" + serviceInstance;}if(status){url += "&status=" + status;}url += "&random=" + Math.random();//alert(url);retrieveURL(url,'viewResult');//tipsWindown("詳細信息","url:get?" + url,"800","700","true","","true","text");}function viewreturn() {var url = contextName + "/viewAction.do?method=viewReturnResult";//時間參數設空document.getElementById("startDate_s").value = "";document.getElementById("endDate_s").value = "";url += "&random=" + Math.random();retrieveURL(url,'viewResult');//tipsWindown("詳細信息","url:get?" + url,"800","700","true","","true","text");}</script><html:form action="/viewAction.do?method=viewExportPDF"><table class="form_t" style="width:100%"><tr><td><input type="submit" id="submit" name="submit" value="導出" class="button4C"/></td></tr></table>
</html:form>
<html:form action="/viewAction.do?method=viewResult" ><table class="form_t" style="width:100%"><tr><th class="tablelogo" colspan="3">統計時間</th></tr><tr><td style="width: 175px; text-align: right;">開始時間</td><td>?<input type="text" name="startDate_s" id="startDate_s"class="Wdate"οnclick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss',maxDate:'#F{$dp.$D(\'endDate_s\')||\'%y-%M-%d %H:{%m-1}:%s\'}'})" /></td><td><input type="hidden" name="serviceInstance" id="serviceInstance" value=""/><input type="hidden" name="status" id="status" value=""/></td></tr><tr><td style="width: 175px; text-align: right;">結束時間</td><td>?<input type="text" name="endDate_s" id="endDate_s" class="Wdate"οnclick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm:ss',minDate:'#F{$dp.$D(\'startDate_s\')}',maxDate:'%y-%M-%d %H:%m:%s'})" /></td><td></td></tr><tr><td style="padding-left: 175px;" colspan="2"><input type="button" value="查看" class="button4C"οnclick="javascript:viewForm(this.form,'viewResult');" /><input type="button" value="返回" class="button4C"οnclick="javascript:viewreturn();" /></td><td>?</td></tr></table>
</html:form>
<table width="100%"><tr><td id="viewResult" width="100%"></td></tr>
</table>
?
java代碼:
[java] view plaincopyprint?
public ?void ?viewExportPDF(ActionMapping?mapping,?ActionForm?form,??????????????HttpServletRequest?request,?HttpServletResponse?response)?? ????????????throws ?Exception?{?? ????????ServletContext?sc?=?request.getSession().getServletContext();?? ????????String?rootpath?=?sc.getRealPath("" );??? ?????????? ????????rootpath?=?rootpath.replaceAll("\\\\",?" /");??? ?????????? ????????String?pdfPathName?=?rootpath?+?"/WebReport.pdf" ;?? ????????ArrayList<String>?list?=?new ?ArrayList<String>();?? ????????for (int ?i=0 ;i<outstreamlist.size();i++)?{?? ????????????list.add(outstreamlist.get(i));?? ????????}?? ?????????? ????????boolean ?flag?=?createPdf(list,?pdfPathName,?request,?response);?? ????????if ?(flag?==?true )?{?? ?????????????? ????????????try ?{?? ????????????????OutputStream?out?=?response.getOutputStream();?? ????????????????byte ?by[]?=?new ?byte [1024 ];?? ????????????????File?fileLoad?=?new ?File(pdfPathName);?? ????????????????response.reset();?? ????????????????response.setContentType("application/pdf" );?? ????????????????response.setHeader("Content-Disposition" ,?? ????????????????"attachment;?filename=WebReport.pdf" );?? ????????????????long ?fileLength?=?fileLoad.length();?? ????????????????String?length1?=?String.valueOf(fileLength);?? ????????????????response.setHeader("Content_Length" ,?length1);?? ????????????????FileInputStream?in?=?new ?FileInputStream(fileLoad);?? ????????????????int ?n;?? ????????????????while ?((n?=?in.read(by))?!=?-1 )?{?? ????????????????????out.write(by,?0 ,?n);?? ????????????????}?? ????????????????in.close();?? ????????????????out.flush();?? ?????????????????? ????????????}?catch (Exception?e)?{?? ????????????????e.printStackTrace();?? ????????????}?? ????????}?else ?{?? ????????????renderText(response,?ERR_MESSAGE);?? ????????}?? ????????return ?;?? ?????????? ????}?? ?????? ?????? ????public ?boolean ?createPdf(ArrayList<String>?list,?String?pdfPathName,?? ????????????HttpServletRequest?request,?HttpServletResponse?response)?? ????????????throws ?Exception?{?? ?????????? ????????? ? ? ? ?? ????????ServletContext?sc?=?request.getSession().getServletContext();?? ????????String?rootpath?=?sc.getRealPath("" );??? ???????? ?? ????????rootpath?=?rootpath.replaceAll("\\\\",?" /");??? ?????????? ????????boolean ?flag?=?false ;?? ????????String?outputFile?=?pdfPathName;?? ?????????? ????????OutputStream?os?=?new ?FileOutputStream(outputFile);?? ????????ITextRenderer?renderer?=?new ?ITextRenderer();?? ????????StringBuffer?html?=?new ?StringBuffer();?? ???????? ?? ????????html.append("<!DOCTYPE?html?PUBLIC?\"-//W3C//DTD?XHTML?1.0?Transitional//EN\"?\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" );?? ????????html.append("<html?xmlns=\"http://www.w3.org/1999/xhtml\">" )?? ????????????.append("<head>" )?? ????????????.append("<meta?http-equiv=\"Content-Type\"?content=\"text/html;?charset=UTF-8\"?/>" )?? ????????????.append("<style?type=\"text/css\"?mce_bogus=\"1\">body?{font-family:?SimSun;}</style>" )?? ????????????.append("<style?type=\"text/css\">img?{width:?500px;}</style>" )?? ????????????.append("<style?type=\"text/css\">table?{font-size:13px;}</style>" )?? ????????????.append("</head>" )?? ????????????.append("<body>" );?? ????????html.append("<center>" );?? ????????html.append("<h1>統計報表</h1>" );?? ????????for (int ?i=0 ;i<list.size();i++)?{?? ????????????html.append("<div>" ?+?list.get(i)?+?"</div>" );?? ????????}?? ????????html.append("</center>" );?? ????????html.append("</body></html>" );?? ????????try ?{?? ????????????renderer.setDocumentFromString(html.toString());?? ?????????????? ????????????renderer.getSharedContext().setBaseURL("file:/" ?+?rootpath);?? ????????????renderer.layout();?? ????????????renderer.createPDF(os);?? ????????????os.close();?? ????????????flag?=?true ;?? ????????}?catch ?(Exception?e)?{?? ????????????flag?=?false ;?? ????????????e.printStackTrace();?? ????????}?? ????????return ?flag;?? ????}??
public void viewExportPDF(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)throws Exception {ServletContext sc = request.getSession().getServletContext();String rootpath = sc.getRealPath(""); //值為D:\apache-tomcat-6.0.26\webapps\webmonitor//把路徑中的反斜杠轉成正斜杠rootpath = rootpath.replaceAll("\\\\", "/"); //值為D:/apache-tomcat-6.0.26/webapps/webmonitor//臨時存儲目錄String pdfPathName = rootpath + "/WebReport.pdf";ArrayList<String> list = new ArrayList<String>();for(int i=0;i<outstreamlist.size();i++) {list.add(outstreamlist.get(i));}//調用方法boolean flag = createPdf(list, pdfPathName, request, response);if (flag == true) {//要實現另存為下載,必須滿足兩個條件:導入commons-upload.jar包,表單提交try {OutputStream out = response.getOutputStream();byte by[] = new byte[1024];File fileLoad = new File(pdfPathName);response.reset();response.setContentType("application/pdf");response.setHeader("Content-Disposition","attachment; filename=WebReport.pdf");long fileLength = fileLoad.length();String length1 = String.valueOf(fileLength);response.setHeader("Content_Length", length1);FileInputStream in = new FileInputStream(fileLoad);int n;while ((n = in.read(by)) != -1) {out.write(by, 0, n);}in.close();out.flush();} catch(Exception e) {e.printStackTrace();}} else {renderText(response, ERR_MESSAGE);}return ;}//生成pdfpublic boolean createPdf(ArrayList<String> list, String pdfPathName,HttpServletRequest request, HttpServletResponse response)throws Exception {/*** 用rootpath指定目錄也可以生成pdf文件,只不過不能在myeclipse的左邊導航窗口中看不到而已* 左邊導航窗口對應C盤目錄下的workspace目錄下程序* 用rootpath指定的目錄是D盤Tomcat目錄*/ServletContext sc = request.getSession().getServletContext();String rootpath = sc.getRealPath(""); //值為D:\apache-tomcat-6.0.26\webapps\webmonitor//把路徑中的反斜杠轉成正斜杠rootpath = rootpath.replaceAll("\\\\", "/"); //值為D:/apache-tomcat-6.0.26/webapps/webmonitorboolean flag = false;String outputFile = pdfPathName;//指定目錄導出文件OutputStream os = new FileOutputStream(outputFile);ITextRenderer renderer = new ITextRenderer();StringBuffer html = new StringBuffer();//組裝成符合W3C標準的html文件,否則不能正確解析html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">").append("<head>").append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />").append("<style type=\"text/css\" mce_bogus=\"1\">body {font-family: SimSun;}</style>").append("<style type=\"text/css\">img {width: 500px;}</style>").append("<style type=\"text/css\">table {font-size:13px;}</style>").append("</head>").append("<body>");html.append("<center>");html.append("<h1>統計報表</h1>");for(int i=0;i<list.size();i++) {html.append("<div>" + list.get(i) + "</div>");}html.append("</center>");html.append("</body></html>");try {renderer.setDocumentFromString(html.toString());// 解決圖片的相對路徑問題,圖片路徑必須以file開頭renderer.getSharedContext().setBaseURL("file:/" + rootpath);renderer.layout();renderer.createPDF(os);os.close();flag = true;} catch (Exception e) {flag = false;e.printStackTrace();}return flag;}
?
?
?
?
?
?
?在Java世界,要想生成PDF,方案不少。最近一直在和這個東西打交道,所以簡單做一個小結吧。 在此之前,先來勾畫一下我心中比較理想的一個解決方案。在企業應用中,碰到的比較多的PDF的需求,可能是針對某個比較典型的具備文檔特性的內容,導出成為PDF進行存檔。由于我們現在往往使用一些開源框架,諸如ssh來構建我們的應用,所以我們相對熟悉的方案是針對具體的業務邏輯設計實體,使用開源框架來實現我們的業務邏輯。而PDF的導出,最好不要破壞現有的程序框架,甚至能復用我們業務邏輯層的代碼。 因為如果把PDF作為一種特殊的表現形式的話,實際上它有點類似模板。最佳的情況,是我們能夠通過編寫某種模板,把PDF的大概樣子確定下來,然后把數據和模板做一次整合,得到最后的結果 帶著這個目標,開始在網上搜索解決方案。也找到了一些方案,下面簡單小結一下: Jasper Report 看到的市面上采用的最多的方案,是Jasper Report。相關的文檔也很多,不過很雜,需要完全掌握,我認為還是有些坡度和時間的。這個時間和坡度我認為主要來自于對iReport這個IDE的反復嘗試,對里面的每個屬性的摸索。 Jasper Report的設計思路,本身是不違反我上面所說的初衷的。因為我們的努力方向是先生成模板,然后得到數據,最后將兩者整合得到結果。但是Jasper Report的問題在于,其生成模板的方式過于復雜,即使有IDE的幫助,我們還是需要對其中的眾多規則有所了解才行,否則就會給調試帶來極大的麻煩。 所以,我認為Jasper Report是一個半調子方案,這種強依賴于IDE進行可視化編輯的方式令我很不爽。同時,由此帶來的諸多的限制,相信也讓很多使用者頗為頭疼。在經歷了一番痛苦的掙扎后,決定放棄使用這種方案。 iText 其實Jasper Report是基于iText的。于是有的人會說,那么直接使用iText不是一種倒退么?的確,直接使用iText似乎就需要直接使用原生的API進行編程了。不過幸好iText其實提供了一些方便的API,通過使用這些API,我們可以直接將HTML代碼轉化成iText可識別的Document對象,從而導出PDF文檔。
java代碼:
[java] view plaincopyprint?
import ?java.io.FileOutputStream;?????import ?java.io.FileReader;?????import ?java.util.ArrayList;????????? import ?com.lowagie.text.Document;?????import ?com.lowagie.text.Element;?????import ?com.lowagie.text.html.simpleparser.HTMLWorker;?????import ?com.lowagie.text.html.simpleparser.StyleSheet;?????import ?com.lowagie.text.pdf.PdfWriter;????????? public ?class ?MainClass?{???????public ?static ?void ?main(String[]?args)?throws ?Exception?{????? ????Document?document?=?new ?Document();????? ????StyleSheet?st?=?new ?StyleSheet();????? ????st.loadTagStyle("body" ,?"leading" ,?"16,0" );????? ????PdfWriter.getInstance(document,?new ?FileOutputStream("html2.pdf" ));????? ????document.open();????? ????ArrayList?p?=?HTMLWorker.parseToList(new ?FileReader("example.html" ),?st);????? ????for ?(int ?k?=?0 ;?k?<?p.size();?++k)????? ??????document.add((Element)?p.get(k));????? ????document.close();????? ??}????? }????
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList; import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.html.simpleparser.StyleSheet;
import com.lowagie.text.pdf.PdfWriter; public class MainClass { public static void main(String[] args) throws Exception { Document document = new Document(); StyleSheet st = new StyleSheet(); st.loadTagStyle("body", "leading", "16,0"); PdfWriter.getInstance(document, new FileOutputStream("html2.pdf")); document.open(); ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st); for (int k = 0; k < p.size(); ++k) document.add((Element) p.get(k)); document.close(); }
}
這是從網上找到的一個例子。從代碼中,我們可以看到,iText本身提供了一個簡單的HTML的解析器,它可以把HTML轉化成我們需要的PDF的document。 有了這個東西,基本上我的目標就能達成一大半了。接下來我的任務就是根據實際情況去編寫HTML代碼,然后扔進這個方法,就OK了。而真正的HTML代碼,我們則可以在這里使用真正的模板技術,Freemarker或者Velocity去生成我們所需要的內容。當然,這已經是我們熟門熟路的東西了。 正當我覺得這個方案基本能符合我的要求的時候,我也同樣找到了它的很多弱項: 1. 無法識別很多HTML的tag和attribute(應該是iText的HTMLParser不夠強大) 2. 無法識別CSS 如果說第一點我還可以勉強接受的話,那么第二點我就完全不能接受了。無法識別簡單的CSS,就意味著HTML失去了最基本的活力,也無法根據實際要求調整樣式。 所以這種方案也必然無法成為我的方案。 flying sauser 在這種情況下,我幾乎已經燃起了自己編寫一個支持CSS解析的HTML Parser的想法。幸好,在一個非常偶然的情況下,我在google中搜到了這樣一個開源項目,它能夠滿足我的一切需求。這就是flying sauser,項目主頁是:https://xhtmlrenderer.dev.java.net/ 項目的首頁非常吸引人:An XML/XHTML/CSS 2.1 Renderer 。這不正是我要的東西么? 仔細再看里面的文檔:
引用
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.
完美了。這東西能解析HTML和CSS,而且能輸出成image,PDF等格式。哇!我們來看看sample代碼(代碼丑陋,不過已經能說明問題了): java代碼:
[java] view plaincopyprint?
? ? ? ? ???? ???? package ?itext;????????? import ?java.io.File;?????import ?java.io.FileOutputStream;?????import ?java.io.OutputStream;????????? import ?org.xhtmlrenderer.pdf.ITextFontResolver;?????import ?org.xhtmlrenderer.pdf.ITextRenderer;????????? import ?com.lowagie.text.pdf.BaseFont;????????? ? ? ? ? ? ? ???? public ?class ?ITextRendererTest?{?????????public ?static ?void ?main(String[]?args)?throws ?Exception?{????? ????????String?inputFile?=?"conf/template/test.html" ;????? ????????String?url?=?new ?File(inputFile).toURI().toURL().toString();????? ????????String?outputFile?=?"firstdoc.pdf" ;????? ????????OutputStream?os?=?new ?FileOutputStream(outputFile);????? ????????ITextRenderer?renderer?=?new ?ITextRenderer();????? ????????renderer.setDocument(url);????? ???? ?????????? ????????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(os);????? ????????????? ????????os.close();????? ????}????? }????
/*
* ITextRendererTest.java *
* Copyright 2009 Shanghai TuDou.
* All rights reserved.
*/ package itext; import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream; import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer; import com.lowagie.text.pdf.BaseFont; /** * TODO class description * * * @author pcwang * * @version 1.0, 上午11:03:26 create $Id$ */
public class ITextRendererTest { public static void main(String[] args) throws Exception { String inputFile = "conf/template/test.html"; String url = new File(inputFile).toURI().toURL().toString(); String outputFile = "firstdoc.pdf"; OutputStream os = new FileOutputStream(outputFile); ITextRenderer renderer = new ITextRenderer(); renderer.setDocument(url); // 解決中文支持問題 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(os); os.close(); }
}
運行,成功!實在太簡單了!API幫你完成了一切! 有了這個東西,我們就可以將PDF的生成流程變成這樣: 1) 編寫Freemarker或者Velocity模板,打造HTML,勾畫PDF的樣式(請任意使用CSS) 2) 在你的業務邏輯層引入Freemarker的引擎或者Velocity的引擎,并將業務邏輯層中可以獲取的數據和模板,使用引擎生成最終的內容 3) 將我上面的sample代碼做簡單封裝后,調用,生成PDF 這樣,我想作為一個web程序員來說,上面的3點,都不會成為你的絆腳石。你可以輕松駕馭PDF了。 在Flying Saucer的官方文檔中,有一些Q&A,可以解決讀者們大部分的問題。包括PDF的字體、PDF的格式、Image如何處理等等。大家可以嘗試著去閱讀。 還有一篇文章,好像是作者寫的,非常不錯:http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html
?
?
Freemarker+Flying sauser +Itext 整合生成PDF
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實踐:
測試數據模型:
java代碼:
[java] view plaincopyprint?
package ?com.jeemiss.pdfsimple.entity;????????? public ?class ?User?{?????????????? ????private ?String?name;????? ????private ?int ?age;????? ????private ?int ?sex;????? ????????? ????? ? ? ? ? ? ???? ????public ?User(String?name,?int ?age,?int ?sex)?{????? ????????super ();????? ????????this .name?=?name;????? ????????this .age?=?age;????? ????????this .sex?=?sex;????? ????}????? ????????? ?????? ????????? ????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.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; } }
java代碼:
[java] view plaincopyprint?
package ?com.jeemiss.pdfsimple.freemarker;????????? import ?freemarker.template.Configuration;????????? public ?class ?FreemarkerConfiguration?{?????????????? ????private ?static ?Configuration?config?=?null ;????? ????????? ????? ? ? ? ???? ????static {????? ????????config?=?new ?Configuration();????? ????????config.setClassForTemplateLoading(FreemarkerConfiguration.class ,?"template" );????? ????}????? ????????? ????public ?static ?Configuration?getConfiguation(){????? ????????return ?config;????? ????}????? ???? }????
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生成器:
java代碼:
[java] view plaincopyprint?
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?{?????????????? ????? ? ? ? ? ? ? ???? ????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;????? ????}????? ???? }????
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生成器:
java代碼:
[java] view plaincopyprint?
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?{????????? ????? ? ? ? ? ? ???? ????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();????? ????}????? ???? }????
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] view plaincopyprint?
< 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 > ?????
<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>
最后寫個測試用例看看:
java代碼:
[java] view plaincopyprint?
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();????? ???????}????? ???????????? ???}????? }????
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(); } }
}
?
到C盤下打開sample.pdf ,看看輸出的結果:
?
?
flying saucer 使用中的一些問題 (java導出pdf)
flying saucer(源代碼托管在githubhttps://github.com/flyingsaucerproject/flyingsaucer)是java導出pdf的一種解決方案,最早是從downpour老大的文章里看到它:http://www.iteye.com/topic/509417 ,感覺比之前的iText好用許多,它可以解析css,即我將頁面先設置好,然后傳遞給它,它既可以給我生成一個pdf出來,跟頁面一樣,當時感覺很酷,于是就研究了一下,現在項目中也用到了,效果還不錯。 ?? ???? 優點很明顯,之前也提到了,可以解析css,這樣很方便,大大的減少了工作量。pdf加水印也變得很簡單——只需為body設置一個background-image即可。 ???? 說說使用中需要注意的一些問題吧: [list=1]
中文換行問題 ?? 老外做的東西,沒有考慮到中文問題。默認提供的包里,中文不會換行,有人修改了源代碼,解決了這個問題,重新編譯好的包在附件里,可以下載。需要注意的是,在官網提供的jar包里,有兩個包,一個是core-renderer.jar,另一個是core-renderer-minimal.jar。引用時,只需引用前者就行。有人曾經說用這個重新編譯后的包替換了原來的包之后,不起作用,原因就在此。 ?
中文換行包下載地址:http://community.csdn.net/detail/shanliangliuxing
?? 另外,想要中文換行,如果是table,那么table 的style必須加上這句話
html代碼:
[html] view plaincopyprint? style ="table-layout:fixed;?word-break:break-strict;" ???? style="table-layout:fixed; word-break:break-strict;" ?
css路徑問題 ?? 在一個java project里,使用相對css路徑是可以的,效果也都不錯。但在java web project里,使用css相對路徑是不可以的(最起碼這里困擾了我很久,差點就放棄flying saucer了)。例如,我有一個模板叫addOne.jsp,里面引用到了某個css,就應該這樣寫(windows)
js代碼:
[javascript] view plaincopyprint? <link?href="file:///D|/project/WebContent/commons/css/module-pdf.css" ?rel="stylesheet" ?type="text/css" ?/>??? <link href="file:///D|/project/WebContent/commons/css/module-pdf.css" rel="stylesheet" type="text/css" /> 只有這樣寫了之后,它才能找到這個css,很詭異。每次換了機器之后都要改路徑,很麻煩。
中文字體問題 ?? downpour老大在它那篇文章里提到了怎樣處理中文字體的,他可能高估了許多人的水平。其實說起來,很簡單,就兩點:一是在java代碼里引用字體,二是在頁面上引用字體。 ? 引用字體: java代碼: ?
[java] view plaincopyprint? ?? ????????ITextFontResolver?fontResolver?=?renderer.getFontResolver();??????? ???????fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf" ,?BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);???? // 解決中文支持問題 ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); 這里引用了arialuni.ttf字體,它位于C盤windows/fonts文件夾下,將它引用后,還需要在頁面上使用這個字體?? html代碼:
[html] view plaincopyprint? < body ?style ="font-family:'Arial?Unicode?MS'" > ???? <body style="font-family:'Arial Unicode MS'">
這里的Arial Unicode MS 即剛才 的arialuni.ttf字體的名字,換了其它字體后要注意修改這里的名稱。這樣才可以在pdf中顯示中文。 ? 許多人有這樣一個問題——按照以上兩個步驟做了之后,頁面中還是沒有中文,這時,請檢查你引用的css文件,其中一定設置了其它字體,只需將它去掉即可
缺點: ??? 我在使用中發現,flying saucer不支持富文本 ,如果用到了KindEditor此類富文本編輯器, 還要將其中的內容轉化成pdf,那對flying saucer來說就是個災難。會報一堆錯誤,目前我還沒有找到解決方案。還好這次項目中不是必須使用富文本編輯器,對于有此類需求的同學來說,請慎重選擇flying saucer。另外,flying saucer嚴格遵守html規則,一個小小的錯誤,都會導致它報錯。諸如 html代碼:
[html] view plaincopyprint? < td ?colspan ="2" "2"> ???? <td colspan="2""2">
此類的html代碼在jsp中是不會有問題的,可是flying saucer卻會報錯,曾經這個問題導致我花了一小時時間來尋找問題所在。不過很難說這到底是缺點還是優點 ??? 最后貼一個較完整的例子: ??? 我使用spring mvc,在controller里 java代碼:
[java] view plaincopyprint? @RequestMapping ("/pdf/{projectId}" )?????????public ?ModelAndView?generatePdf(HttpServletRequest?request,????? ????????????HttpServletResponse?response,?@PathVariable ???? ????????????String?projectId)?{????? ????????Project?project?=?this .projectService.getProjectById(projectId);????? ????????ModelAndView?mav?=?new ?ModelAndView();????? ????????if ?(project?==?null )?{????? ????????????mav.setViewName("forward:/error/page-not-found" );????? ????????????return ?mav;????? ????????}????? ???????????????? ?? ????????String?pdfName?=?"pdfName" ;????? ????????????? ????????????response.setHeader("Content-disposition" ,?"attachment;filename=" +pdfName;????? ????????????response.setContentType("application/pdf" );????? ????????????OutputStream?os?=?response.getOutputStream();????? ????????????ITextRenderer?renderer?=?new ?ITextRenderer();????? ?? renderer.setDocument("http://localhost/project/preview/" +projectId);????? ????????????????? ????????????ITextFontResolver?fontResolver?=?renderer.getFontResolver();????? ????????????if ?(StringUtils.isOSWindow())????? ????????????????fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF" ,????? ????????????????????????BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);????? ????????????else ???? ????????????????fontResolver.addFont("/usr/share/fonts/TTF/ARIALUNI.TTF" ,????? ????????????????????????BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);????? ????????????renderer.layout();????? ????????????renderer.createPDF(os);????? ????????????os.close();????? ????????????? ????????return ?null ;????? ????}????? ???? ????????@RequestMapping ("/preview/{projectId}" )????? ????????public ?ModelAndView?pdf(@PathVariable ???? ????????String?projectId)?{????? ????????????Project?project?=?this .projectService.getProjectById(projectId);????? ????????????ModelAndView?mav?=?new ?ModelAndView();????? ????????????if ?(project?==?null )?{????? ????????????????mav.setViewName("forward:/error/page-not-found" );????? ????????????????return ?mav;????? ????????????}????? ????????????mav.setViewName("pdf" );????? ????????????mav.addObject("project" ,project);????? ????????????return ?mav;????? ????????}????? @RequestMapping("/pdf/{projectId}") public ModelAndView generatePdf(HttpServletRequest request, HttpServletResponse response, @PathVariable String projectId) { Project project = this.projectService.getProjectById(projectId); ModelAndView mav = new ModelAndView(); if (project == null) { mav.setViewName("forward:/error/page-not-found"); return mav; } //中文需轉義 String pdfName = "pdfName"; response.setHeader("Content-disposition", "attachment;filename="+pdfName; response.setContentType("application/pdf"); OutputStream os = response.getOutputStream(); ITextRenderer renderer = new ITextRenderer();
//指定模板地址
renderer.setDocument("http://localhost/project/preview/"+projectId); ITextFontResolver fontResolver = renderer.getFontResolver(); if (StringUtils.isOSWindow()) fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); else fontResolver.addFont("/usr/share/fonts/TTF/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); renderer.layout(); renderer.createPDF(os); os.close(); return null; } @RequestMapping("/preview/{projectId}") public ModelAndView pdf(@PathVariable String projectId) { Project project = this.projectService.getProjectById(projectId); ModelAndView mav = new ModelAndView(); if (project == null) { mav.setViewName("forward:/error/page-not-found"); return mav; } mav.setViewName("pdf"); mav.addObject("project",project); return mav; }
jsp頁面如下
html代碼:
[html] view plaincopyprint? ?< html ?xmlns ="http://www.w3.org/1999/xhtml" > ???? < head > ????< meta ?http-equiv ="Content-Type" ?content ="text/html;?charset=utf-8" ?/> ????< title > title</ title > ????< link ?href ="file:///D|/project/WebContent/commons/css/print-pdf.css" ?rel ="stylesheet" ?type ="text/css" ??/> ???????? </ head > ????< body ?style ="font-family:'Arial?Unicode?MS'" > ???????< table ?border ="1" ?cellspacing ="0" ?cellpadding ="0" ?class ="table" ?style ="table-layout:fixed;?word-break:break-strict;" > ???? ????< tr > ???? ??????< td ?rowspan ="9" ?width ="4%" ?class ="tc" > 項目單位基本信息</ td > ???? ??????< td ?colspan ="2" ?style ="width:160px" > (1)項目單位名稱?</ td > ???? ??????< td ?colspan ="2" > < %=StringUtils.getValueString(user.getDeptName())?%> </ td > ???? ????</ tr > ???? ????</ table > ???? </ body > ???? <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>title</title>
<link href="file:///D|/project/WebContent/commons/css/print-pdf.css" rel="stylesheet" type="text/css" /> </head>
<body style="font-family:'Arial Unicode MS'"> <table border="1" cellspacing="0" cellpadding="0" class="table" style="table-layout:fixed; word-break:break-strict;"> <tr> <td rowspan="9" width="4%" class="tc">項目單位基本信息</td> <td colspan="2" style="width:160px">(1)項目單位名稱 </td> <td colspan="2"><%=StringUtils.getValueString(user.getDeptName()) %></td> </tr> </table>
</body>
?
使用flyingsaucer將網頁轉換為pdf之中文問題徹底解決 前幾天遇到個導出pdf 的需求,在網絡上查找了一下java導出pdf 的方案.多數人推薦使用iText,研究了一下,感覺直接寫pdf的方法太笨,可維護性差,一旦pdf格式要變化改起來很費勁.還有一個方案,可以先預先定義一個pdf作為模板文件,然后用業務數據進行填空.是個不錯的方案,只可惜不適合我的需求.需求中有些行是動態加行的,這個方案無法實現.后來發現有可以將網頁直接轉成pdf 的開源包flyingsaucer (中文名:灰碟),逐將注意力轉移到這上面,發現是個不錯的選擇.只要寫網頁就可以了,而且pdf格式變化維護起來也方便,代碼也會比較干凈.只是它對中文支持 的不好,但這不是無法解決的.下面就來說說這個flyingsaucer .
Flyingsaucer 使用iText2.0.8作為其pdf輸出的基礎工具,另外增加了解析html/xml并形成pdf式排版的功能.最重要的它還支持css樣式表.組合這些能力后,它就可以將網頁變成pdf了.但是,它也有他的問題.大家知道iText的版本現在已經升級為5.0以上了,而flyingsaucer 卻依然沿用2.0.8的版本.為什么呢? 因為這個灰碟貌似自2007年就已經停止維護了,最終版本flyingsaucer-R8.也就是說這是個幾年前的工具包,至于新的替代此功能的包又在哪里?我沒有找到,倒是有個功能相似但是收費的,不知道是不是它的成長版.這是題外話我們不研究.只看這個flyingsaucer -R8這個版本能否滿足我們的基本要求吧. 在使用過程中發現flyingsaucer -R8對導出pdf的網頁有一些要求. 1.?所有的標簽必須都閉合. 2.?網頁開頭引入的DTD必須與網頁體中使用的標簽一致. 3.?部分不太常用的html標簽貌似不認.比如<u>. 因為flyingsaucer 解析html文檔是遵照xml標準來的,所以這個網頁寫起來不能像我們平時的網頁那么隨意.xml該有的規則都要遵守.這個要求并不高我們可以做到,而且試了下導出的pdf文檔沒啥問題,因此我們還是可以使用它來滿足我們的需求.(至于,這個工具包怎么用,這里有不多說了,google一下一大片.這里只寫目前google不到的東西.) 既然要用它不可回避的就會遇到其對中文支持 不好的問題. 問題1:來源自渲染器輸出時沒有使用支持中文的字體.雖然我們看到iText有亞洲語言包iTextAsian.jar,但是僅僅引入此包并不能使我們的中文字符輸出.以至于網上有個哥們寫到: 打開ITextOutputDevice這個類找到: java代碼:
[java] view plaincopyprint? cb.setFontAndSize(_font.getFontDescription().getFont(),?_font.getSize2D()?/?_dotsPerPoint);??????? cb.setFontAndSize(_font.getFontDescription().getFont(), _font.getSize2D() / _dotsPerPoint); 改成:
java代碼:
[java] view plaincopyprint? 01 .try ?{????????02 .????????????cb.setFontAndSize(BaseFont.createFont("STSong-Light" ,?"UniGB-UCS2-H" ,?BaseFont.NOT_EMBEDDED),?_font.getSize2D()/_dotsPerPoint);????????03 .????????}?catch ?(Exception?e)?{????????04 .????????}??????? 01.try {
02. cb.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), _font.getSize2D()/_dotsPerPoint);
03. } catch (Exception e) {
04. } Ok,改了以后我們終于可以看到pdf里有中文了.但是別高興的太早哦,問題并沒有完全解決.如果一段標簽中有且只有中文字符的時候,導出pdf后內容便會消失.比如<div>中文</div>,這樣的代碼將什么也輸出不了,而<div>中文a</div>則會將標簽內容全部輸出.通過測試我們發現,純中文是無法輸出的,但是加上一點點英文、數字或符號就可以輸出了.有同學可能要說我們把純中文后面加上空格不就行了?我只能說很不幸,加空格是不管用的.如果你的頁面上純中文的地方可以隨便讓你加字母/數字/符號,那可以不必往下看了.但是我覺得大多數的人恐怕不會這么干的,即使我們想客戶也不讓啊.那就要解決這個問題.
開源的東西有個好處,可以看源代碼.從源碼中我發現是字體的問題,于是乎,google一下,找到以下方案: 在導出的代碼里加入這兩句引入字體 java代碼:
[java] view plaincopyprint? 01 .ITextFontResolver?fontResolver?=?renderer.getFontResolver();???????????02 .fontResolver.addFont("C:/WINDOWS/Fonts/ARIALUNI.TTF" ,?BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);??????? 01.ITextFontResolver fontResolver = renderer.getFontResolver();
02.fontResolver.addFont("C:/WINDOWS/Fonts/ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); 于是我照做了.杯具的是情況沒有任何好轉.即使有好轉這個絕對路徑的字體引入方式也很讓人不舒服吧.所以這個不是我們想要的解決方案.
Google不到只能繼續從代碼里找辦法了.通過跟深入的研究代碼,發現問題根源所在.輸出PDF時在計算字符寬度的時候,對中文字符計算出的寬度居然是0.這也就能解釋為什么純中文字符串輸出后會看不到了,因為字符總體的寬度被計算為0也就失去了被輸出的機會,而加上一點非中文字符的則至少會有一點寬度,即獲得了輸出的機會,即使實際寬度比計算的寬度要寬也是可以輸出的. 于是修改BaseFont中的getWidth(String text)方法 java代碼:
[java] view plaincopyprint? 01 .if ?(char1?<?128 ?||?(char1?>=?160 ?&&?char1?<=?255 ))????????02 .????total?+=?widths[char1];????????03 .else ???????04 .????total?+=?widths[PdfEncodings.winansi.get(char1)];??????? 01.if (char1 < 128 || (char1 >= 160 && char1 <= 255))
02. total += widths[char1];
03.else
04. total += widths[PdfEncodings.winansi.get(char1)]; 這幾行改為:
java代碼:
[java] view plaincopyprint? ·········10 ········20 ········30 ········40 ········50 ········60 ········70 ········80 ········90 ········100 ·······110 ·······120 ·······130 ·······140 ·······15001 .if ?(char1?<?128 ?||?(char1?>=?160 ?&&?char1?<=?255 ))???????? 02 .????total?+=?widths[char1];????????03 .else ?if ?((char1?>=?19968 )?&&?(char1?<=?40869 ))???04 .????total?+=?500 ;????????05 .else ???????06 .????total?+=?widths[PdfEncodings.winansi.get(char1)];??????? ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.if (char1 < 128 || (char1 >= 160 && char1 <= 255))
02. total += widths[char1];
03.else if ((char1 >= 19968) && (char1 <= 40869)) // 如果是中文字符加寬度500
04. total += 500;
05.else
06. total += widths[PdfEncodings.winansi.get(char1)]; 再次測試,通過.至此,使用flyingsaucer 將網頁導出成pdf 的中文問題 總算解決了.可是總覺得這個解決的方法有點不太正宗,因為修改了父類嘛.但又沒有找到其他正宗的解決方案,只能先這樣解決一下了.發出此文,只當拋磚引玉,如果有哪位高人有更好的解決方案請不吝賜教啊.
??? 附件提供修改了的flyingsaucer -R8的兩個jar包: core-renderer.jar和iText2.0.8.jar另有一個iText亞洲語言包.
下載修改源碼后的jar包地址:http://download.csdn.net/detail/shanliangliuxing/3640286
?
?
?
利用 iText 實現 PDF 報表下載 (沒有用flying saucer) 很久沒更新 blog 了,工作和一些事情占用了大部分精力,實在是身不由己。今天終于有空整理一下最近用到的東西。 有個朋友的項目需要用到 PDF 報表下載,之前我只做過 Excel 的,相信再做一次 PDF 的下載一定很有趣吧。在網上找了一大圈,似乎 iText 比較符合我的要求,而且這個工具很早很早以前就有了,生命力很旺盛。進入 iText 的主頁(http://www.lowagie.com/iText/),發現作者很勤勞,最近2個月都有新版本發布。哪知道現在高興得太早了,一堆問題接踵而至。 下載倒是很簡單,一個iText-2.1.4.jar搞定,然后去找入門文檔,進了文檔頁面,一股濃郁的商業氣氛迎面而來,這里只提供了部分文檔,除非去買"iText in Action",隨后被踢到 iText by Example 頁面。好吧,既然這是老牌工具了,肯定有不少中文資料吧,找了一圈,沒發現什么和生成并下載相關的 out of box 文檔,很多都是經驗性的總結和進階文章。無奈又啃 iText by Example,在這里找到些有用的資源,iText in a Web Application正是我要找的,不過這個例子很簡單。通過 Google 之后,又發現要下載一個 CJK 的包(iTextAsian.jar)才能正確顯示中文,好吧我去找。很幸運的是在 iText by Example 里找到了這個 jar 的 link,興致勃勃的跑去下載,結果這是個無效鏈接,最后在 sourceForge 上才找到,不容易啊。解決了這些問題,想必能夠安穩的使用了吧,由于這個項目比較急,沒什么耐心一個個的翻閱 iText by Example,想找點捷徑,據說 iText 可以從 html 直接生成 PDF,竊喜!找了 apache common 的 httpclient,動態模擬 http 請求來抓 html,根據控制臺的 print,的確把 html 抓到了,然后開始轉換到 PDF,先解決了中文顯示問題,可是后面的問題解決不了了,html 的 table 和 div 這些,轉換到 PDF 都走樣了... ... 很不爽,看來還是只有老老實實的啃 iText by Example實在點。這次稍微耐心點,一點點的看,首先搞清楚了它的 Font 設置,然后是 Table 和 Cell 的關系,經過反復調試,有點效果了。把代碼貼出來,做個標記吧。以免以后又抓狂。
java代碼:
[java] view plaincopyprint? 1 ?package ?org.rosenjiang.servlet;????2 ??? ??3 ?import ?java.awt.Color;?? ??4 ?import ?java.io.IOException;?? ??5 ?import ?java.util.HashMap;?? ??6 ?import ?java.util.List;?? ??7 ?import ?java.util.Map;?? ??8 ??? ??9 ?import ?javax.servlet.ServletException;?? ?10 ?import ?javax.servlet.http.HttpServlet;?? ?11 ?import ?javax.servlet.http.HttpServletRequest;?? ?12 ?import ?javax.servlet.http.HttpServletResponse;?? ?13 ??? ?14 ?import ?org.springframework.web.context.WebApplicationContext;?? ?15 ?import ?org.springframework.web.context.support.WebApplicationContextUtils;?? ?16 ??? ?17 ?import ?org.rosenjiang.service.UserService;?? ?18 ?import ?com.lowagie.text.Document;?? ?19 ?import ?com.lowagie.text.DocumentException;?? ?20 ?import ?com.lowagie.text.Font;?? ?21 ?import ?com.lowagie.text.Paragraph;?? ?22 ?import ?com.lowagie.text.pdf.BaseFont;?? ?23 ?import ?com.lowagie.text.pdf.PdfPCell;?? ?24 ?import ?com.lowagie.text.pdf.PdfPTable;?? ?25 ?import ?com.lowagie.text.pdf.PdfWriter;?? ?26 ??? ?27 ?? ? ? ? ??? ?32 ?public ?class ?ReportServlet?extends ?HttpServlet?{?? ?33 ?????????? ?34 ?????? ? ? ?? ?38 ?????public ?void ?doGet?(HttpServletRequest?request,?HttpServletResponse?response)?? ?39 ?????throws ?IOException,?ServletException?{?? ?40 ?????????String?account_id?=?request.getParameter("account_id" );?? ?41 ?????????String?search_date_from?=?request.getParameter("search_date_from" );?? ?42 ?????????String?to?=?request.getParameter("to" );?? ?43 ?????????WebApplicationContext?ctx?=?WebApplicationContextUtils.getWebApplicationContext(this .getServletContext());?? ?44 ?????????UserService?userService?=?(UserService)ctx.getBean("userService" );?? ?45 ?????????List<Map<String,?Object>>?list?=?userService.getAccountActivity(account_id,?search_date_from,?to);?? ?46 ??????????? ?47 ?????????Document?document?=?new ?Document();?? ?48 ?????????try ?{?? ?49 ??????????????? ?50 ?????????????response.setContentType("application/x-msdownload;charset=UTF-8" );?? ?51 ?????????????response.setHeader("Content-Disposition" ,"attachment;filename=report.pdf" );?? ?52 ??????????????? ?53 ?????????????PdfWriter.getInstance(document,?response.getOutputStream());?? ?54 ??????????????? ?55 ?????????????document.open();?? ?56 ??????????????? ?57 ?????????????BaseFont?bfChinese?=?BaseFont.createFont("STSong-Light" ,?"UniGB-UCS2-H" ,?BaseFont.NOT_EMBEDDED);???? ?58 ?????????????Font?f2?=?new ?Font(bfChinese,?2 ,?Font.NORMAL);?? ?59 ?????????????Font?f6?=?new ?Font(bfChinese,?6 ,?Font.NORMAL);?? ?60 ?????????????Font?f8?=?new ?Font(bfChinese,?8 ,?Font.NORMAL);?? ?61 ?????????????Font?f10?=?new ?Font(bfChinese,?10 ,?Font.NORMAL);?? ?62 ?????????????Font?f12?=?new ?Font(bfChinese,?12 ,?Font.BOLD);?? ?63 ??????????????? ?64 ?????????????document.add(new ?Paragraph("金融報表" ,?f12));??? ?65 ??????????????? ?66 ?????????????document.add(new ?Paragraph("?" ,f6));??? ?67 ??????????????? ?68 ?????????????document.add(new ?Paragraph("賬戶信息" ,?f10));??? ?69 ??????????????? ?70 ?????????????document.add(new ?Paragraph("?" ,?f2));?? ?71 ??????????????? ?72 ?????????????if (list.size()>0 ?&&?list.get(0 ).get("bankbook_no" )!=null ){?? ?73 ?????????????????float ?openBalance?=?0 ;?? ?74 ??????????????????? ?75 ?????????????????PdfPTable?table?=?new ?PdfPTable(7 );?? ?76 ??????????????????? ?77 ?????????????????table.setWidthPercentage(100 );?? ?78 ?????????????????table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);?? ?79 ??????????????????? ?80 ?????????????????PdfPCell?cell?=?new ?PdfPCell();?? ?81 ??????????????????? ?82 ?????????????????cell.setBackgroundColor(new ?Color(213 ,?141 ,?69 ));?? ?83 ?????????????????cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);?? ?84 ??????????????????? ?85 ?????????????????cell.setPhrase(new ?Paragraph("交易日" ,?f8));?? ?86 ?????????????????table.addCell(cell);?? ?87 ?????????????????cell.setPhrase(new ?Paragraph("類型" ,?f8));?? ?88 ?????????????????table.addCell(cell);?? ?89 ?????????????????cell.setPhrase(new ?Paragraph("備注" ,?f8));?? ?90 ?????????????????table.addCell(cell);?? ?91 ?????????????????cell.setPhrase(new ?Paragraph("ID" ,?f8));?? ?92 ?????????????????table.addCell(cell);?? ?93 ?????????????????cell.setPhrase(new ?Paragraph("票號" ,?f8));?? ?94 ?????????????????table.addCell(cell);?? ?95 ?????????????????cell.setPhrase(new ?Paragraph("合計" ,?f8));?? ?96 ?????????????????table.addCell(cell);?? ?97 ?????????????????cell.setPhrase(new ?Paragraph("余額" ,?f8));?? ?98 ?????????????????table.addCell(cell);?? ?99 ??????????????????? 100 ?????????????????PdfPCell?newcell?=?new ?PdfPCell();??101 ?????????????????newcell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);??102 ???????????????????103 ?????????????????Map<String,?Object>?map?=?new ?HashMap<String,?Object>();??104 ?????????????????for (int ?i?=?0 ;?i?<?list.size();?i++){??105 ?????????????????????map?=?list.get(i);??106 ?????????????????????String?cashInout?=?map.get("cash_inout" ).toString();??107 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("trade_date" ).toString(),?f8));??108 ?????????????????????table.addCell(newcell);??109 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("bankbook_type" ).toString(),?f8));??110 ?????????????????????table.addCell(newcell);??111 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("memo" ).toString(),?f8));??112 ?????????????????????table.addCell(newcell);??113 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("account_id" ).toString(),?f8));??114 ?????????????????????table.addCell(newcell);??115 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("ticket_no" ).toString(),?f8));??116 ?????????????????????table.addCell(newcell);??117 ?????????????????????newcell.setPhrase(new ?Paragraph(map.get("amount" ).toString(),?f8));??118 ?????????????????????table.addCell(newcell);??119 ?????????????????????newcell.setPhrase(new ?Paragraph(openBalance+"" ,?f8));??120 ?????????????????????table.addCell(newcell);??121 ?????????????????????if (cashInout.equals("I" )){??122 ?????????????????????????openBalance?=?openBalance?+?Float.valueOf(map.get("amount" ).toString());??123 ?????????????????????}else ?if (cashInout.equals("O" )){??124 ?????????????????????????openBalance?=?openBalance?-?Float.valueOf(map.get("amount" ).toString());??125 ?????????????????????}??126 ?????????????????}??127 ???????????????????128 ?????????????????newcell.setPhrase(new ?Paragraph("合計" +openBalance,?f8));??129 ?????????????????table.addCell("" );??130 ?????????????????table.addCell("" );??131 ?????????????????table.addCell("" );??132 ?????????????????table.addCell("" );??133 ?????????????????table.addCell("" );??134 ?????????????????table.addCell("" );??135 ?????????????????table.addCell(newcell);??136 ?????????????????document.add(table);??137 ?????????????}else {??138 ?????????????????PdfPTable?table?=?new ?PdfPTable(1 );??139 ?????????????????table.setWidthPercentage(100 );??140 ?????????????????table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);??141 ?????????????????PdfPCell?cell?=?new ?PdfPCell(new ?Paragraph("暫無數據" ));??142 ?????????????????cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);??143 ?????????????????table.addCell(cell);??144 ?????????????????document.add(table);??145 ?????????????}??146 ?????????}??147 ?????????catch (DocumentException?de)?{??148 ?????????????de.printStackTrace();??149 ?????????????System.err.println("document:?" ?+?de.getMessage());??150 ?????????}finally {??151 ???????????????152 ?????????????document.close();??153 ?????????}??????????154 ?????}??155 ?}?? 1 package org.rosenjiang.servlet;2 3 import java.awt.Color;4 import java.io.IOException;5 import java.util.HashMap;6 import java.util.List;7 import java.util.Map;8 9 import javax.servlet.ServletException;10 import javax.servlet.http.HttpServlet;11 import javax.servlet.http.HttpServletRequest;12 import javax.servlet.http.HttpServletResponse;13 14 import org.springframework.web.context.WebApplicationContext;15 import org.springframework.web.context.support.WebApplicationContextUtils;16 17 import org.rosenjiang.service.UserService;18 import com.lowagie.text.Document;19 import com.lowagie.text.DocumentException;20 import com.lowagie.text.Font;21 import com.lowagie.text.Paragraph;22 import com.lowagie.text.pdf.BaseFont;23 import com.lowagie.text.pdf.PdfPCell;24 import com.lowagie.text.pdf.PdfPTable;25 import com.lowagie.text.pdf.PdfWriter;26 27 /*28 * ReportServlet29 * @author rosen jiang30 * @since 2008-1231 */ 32 public class ReportServlet extends HttpServlet {33 34 /**35 * Return a PDF document for download.36 * 37 */38 public void doGet (HttpServletRequest request, HttpServletResponse response)39 throws IOException, ServletException {40 String account_id = request.getParameter("account_id");41 String search_date_from = request.getParameter("search_date_from");42 String to = request.getParameter("to");43 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());44 UserService userService = (UserService)ctx.getBean("userService");45 List<Map<String, Object>> list = userService.getAccountActivity(account_id, search_date_from, to);46 // create PDF document47 Document document = new Document();48 try {49 //set response info50 response.setContentType("application/x-msdownload;charset=UTF-8");51 response.setHeader("Content-Disposition","attachment;filename=report.pdf");52 //open output stream53 PdfWriter.getInstance(document, response.getOutputStream());54 // open PDF document55 document.open();56 // set chinese font57 BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); 58 Font f2 = new Font(bfChinese, 2, Font.NORMAL);59 Font f6 = new Font(bfChinese, 6, Font.NORMAL);60 Font f8 = new Font(bfChinese, 8, Font.NORMAL);61 Font f10 = new Font(bfChinese, 10, Font.NORMAL);62 Font f12 = new Font(bfChinese, 12, Font.BOLD);63 //set title64 document.add(new Paragraph("金融報表", f12)); 65 //<br>66 document.add(new Paragraph(" ",f6)); 67 //set sub title68 document.add(new Paragraph("賬戶信息", f10)); 69 //<br>70 document.add(new Paragraph(" ", f2));71 //process business data72 if(list.size()>0 && list.get(0).get("bankbook_no")!=null){73 float openBalance = 0;74 //create table with 7 columns75 PdfPTable table = new PdfPTable(7);76 //100% width77 table.setWidthPercentage(100);78 table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);79 //create cells80 PdfPCell cell = new PdfPCell();81 //set color82 cell.setBackgroundColor(new Color(213, 141, 69));83 cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);84 //85 cell.setPhrase(new Paragraph("交易日", f8));86 table.addCell(cell);87 cell.setPhrase(new Paragraph("類型", f8));88 table.addCell(cell);89 cell.setPhrase(new Paragraph("備注", f8));90 table.addCell(cell);91 cell.setPhrase(new Paragraph("ID", f8));92 table.addCell(cell);93 cell.setPhrase(new Paragraph("票號", f8));94 table.addCell(cell);95 cell.setPhrase(new Paragraph("合計", f8));96 table.addCell(cell);97 cell.setPhrase(new Paragraph("余額", f8));98 table.addCell(cell);99 //create another cell
100 PdfPCell newcell = new PdfPCell();
101 newcell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
102
103 Map<String, Object> map = new HashMap<String, Object>();
104 for(int i = 0; i < list.size(); i++){
105 map = list.get(i);
106 String cashInout = map.get("cash_inout").toString();
107 newcell.setPhrase(new Paragraph(map.get("trade_date").toString(), f8));
108 table.addCell(newcell);
109 newcell.setPhrase(new Paragraph(map.get("bankbook_type").toString(), f8));
110 table.addCell(newcell);
111 newcell.setPhrase(new Paragraph(map.get("memo").toString(), f8));
112 table.addCell(newcell);
113 newcell.setPhrase(new Paragraph(map.get("account_id").toString(), f8));
114 table.addCell(newcell);
115 newcell.setPhrase(new Paragraph(map.get("ticket_no").toString(), f8));
116 table.addCell(newcell);
117 newcell.setPhrase(new Paragraph(map.get("amount").toString(), f8));
118 table.addCell(newcell);
119 newcell.setPhrase(new Paragraph(openBalance+"", f8));
120 table.addCell(newcell);
121 if(cashInout.equals("I")){
122 openBalance = openBalance + Float.valueOf(map.get("amount").toString());
123 }else if(cashInout.equals("O")){
124 openBalance = openBalance - Float.valueOf(map.get("amount").toString());
125 }
126 }
127 //print total column
128 newcell.setPhrase(new Paragraph("合計"+openBalance, f8));
129 table.addCell("");
130 table.addCell("");
131 table.addCell("");
132 table.addCell("");
133 table.addCell("");
134 table.addCell("");
135 table.addCell(newcell);
136 document.add(table);
137 }else{
138 PdfPTable table = new PdfPTable(1);
139 table.setWidthPercentage(100);
140 table.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);
141 PdfPCell cell = new PdfPCell(new Paragraph("暫無數據"));
142 cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
143 table.addCell(cell);
144 document.add(table);
145 }
146 }
147 catch(DocumentException de) {
148 de.printStackTrace();
149 System.err.println("document: " + de.getMessage());
150 }finally{
151 // close the document and the outputstream is also closed internally
152 document.close();
153 }
154 }
155 } 執行結果:
?
代碼結構清晰,本來也沒什么東西,就是通過 Spring 調用 service 方法,獲取數據后按照 iText 結構輸出即可。不過代碼里面有個很愚蠢的動作:document.add( new?Paragraph( " ? " ,f6)),主要是找不到如何輸出空白行,所以只好出此下策。如果哪位有解法,請告知一下。 做技術的確不能太著急,慢慢來,總會找到出口的。
?
?
一定要學會看官方文檔,因為有些技術網上的資料太少,簡單的還能滿足需求,復雜一點的就得需要自己慢慢去研究官方文檔了
官方文檔一般都是英文的,所以,英文水平還要過的去才行,說不作要求,最起碼要能讀懂。
?
flying saucer的官方文檔:
http://code.google.com/p/flying-saucer/
官方文檔中關于生成pdf的demo:
http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html
相關例子源文件下載:
https://svn.atlassian.com/svn/public/atlassian/vendor/xhtmlrenderer-8.0/tags/8.3-atlassian/demos/samples/src/
總結
以上是生活随笔 為你收集整理的flying saucer技术生成pdf文档 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。